2016-10-13 3 views
2

Я пытаюсь сортировать массив объектов на основе произвольного свойства внутри объекта. Я написал следующий код, который отлично работает.
Сортировка массива объектов на основе нескольких свойств

var customSort = function(data, sortBy, order) { 
    if (!(data && sortBy)) { 
    throw new Error('Specify the data source and atleast one property to sort it by'); 
    } 
    if (!Array.isArray(data)) { 
    throw new Error('Specify the data source as an array'); 
    } 
    order = order || 'asc'; 

    function performSort(order, sortBy) { 
    return data.sort(function(a, b) { 
     var A = parse(a, sortBy); 
     var B = parse(b, sortBy); 
     if (A < B) { 
     return order === 'asc' ? -1 : 1; 
     } else if (A > B) { 
     return order === 'asc' ? 1 : -1; 
     } else { 
     return 0; 
     } 
    }); 
    } 

    function parse(data, sortBy) { 
    var sortParams = sortBy.split('.'); 
    var latestValue = data; 
    for (var i = 0; i < sortParams.length; i++) { 
     latestValue = latestValue[sortParams[i]]; 
    } 
    if (!latestValue) { 
     throw new Error('Check the \'sortBy\' parameter. Unreachable parameter in \'sortBy\''); 
    } 
    if (typeof latestValue === 'string') { 
     return latestValue.toLowerCase(); 
    } else { 
     return latestValue; 
    } 
    } 

    return performSort(order, sortBy); 
}; 

var lonelyData = [{ 
    a: { 
    b: 2 
    } 
}, { 
    a: { 
    b: 1 
    } 
}, { 
    a: { 
    b: 9 
    } 
}, { 
    a: { 
    b: 7 
    } 
}, { 
    a: { 
    b: 4 
    } 
}, { 
    a: { 
    b: 2 
    } 
}, { 
    a: { 
    b: 1 
    } 
}]; 

console.log(customSort(lonelyData, 'a.b')); 

Fiddle здесь: JSFiddle



Теперь я пытаюсь использовать рекурсию, чтобы сортировать по нескольким свойствам в следующим образом: Во-первых, сортировать по первому свойству, а затем в той же собственности , сортировать по второму свойству и т. д. Для упрощения вещей я принимаю одинаковый порядок для всех свойств, т. Е. Все возрастающие или все уменьшающиеся.
Я написал этот код:

var customSort = function(data, sortBy, order) { 
    if (!(data && sortBy)) { 
    throw new Error('Specify the data source and atleast one property to sort it by'); 
    } 
    if (!Array.isArray(data)) { 
    throw new Error('Specify the data source as an array'); 
    } 
    if (!Array.isArray(sortBy)) { 
    sortBy = [sortBy]; 
    } 
    order = order || 'asc'; 

    function performSort(order, sortBy) { 
    return data.sort(function(a, b) { 
     function nestedSort() { 
     var highestOrder = sortBy[0]; 
     var A = parse(a, highestOrder); 
     var B = parse(b, highestOrder); 
     if (A < B) { 
      return order === 'asc' ? -1 : 1; 
     } else if (A > B) { 
      return order === 'asc' ? 1 : -1; 
     } else { 
      sortBy.shift(); 
      nestedSort(); 
     } 
     } 
     return nestedSort(); 
    }); 
    } 

    function parse(data, sortBy) { 
    var sortParams = sortBy.split('.'); 
    var latestValue = data; 
    for (var i = 0; i < sortParams.length; i++) { 
     latestValue = latestValue[sortParams[i]]; 
    } 
    if (!latestValue) { 
     throw new Error('Check the \'sortBy\' parameter. Unreachable property passed in \'sortBy\''); 
    } 
    if (typeof latestValue === 'string') { 
     return latestValue.toLowerCase(); 
    } else { 
     return latestValue; 
    } 
    } 

    return performSort(order, sortBy); 
}; 

var lonelyData = [{ 
    a: { 
    b: 2, 
    c: 'Z' 
    } 
}, { 
    a: { 
    b: 2, 
    c: 'A' 
    } 
}, { 
    a: { 
    b: 9, 
    c: 'Q' 
    } 
}, { 
    a: { 
    b: 7, 
    c: 'L' 
    } 
}, { 
    a: { 
    b: 7, 
    c: 'E' 
    } 
}, { 
    a: { 
    b: 1, 
    c: 'A' 
    } 
}, { 
    a: { 
    b: 1, 
    c: 'B' 
    } 
}]; 

console.log(customSort(lonelyData, ['a.b', 'a.c'])); 

скрипку здесь: JSFiddle


К сожалению, я не мог заставить его работать. Что мне здесь не хватает?

+0

немного запутался здесь .... если SortBy есть [a.b, a.c], то вы хотите, чтобы массив будет отсортирован по порядку, а затем сортируются в алфавитном порядке? –

+0

@ LucasKot-Zaniewski Если sortBy является [a.b, a.c], тогда массив должен сортироваться численно (на основе a.b), а затем для тех же значений чисел (a.b), массив должен быть отсортирован в алфавитном порядке (на основе a.c). Например, это должно выглядеть так: [{a: {b: 1, c: 'A'}}, {a: {b: 1, c: 'B'}}, {a: {b: 2, c : 'A'}}, {a: {b: 2, c: 'Z'}} ....... так далее] для вышеуказанного тестового примера – Ozil

ответ

3
 sortBy.shift(); 
    nestedSort(); 

ваша проблема. shift действительно мутирует массив и бросает первый элемент навсегда. В следующий раз, когда функция сравнения вызывается для сравнения a с b, она будет проигнорирована, и вскоре массив будет пуст, и ваш сорт полностью сломается.

Вместо этого используйте простой цикл:

return data.sort(function(a, b) { 
    for (var i=0; i<sortBy.length; i++) 
    var currentOrder = sortBy[i]; 
    var A = parse(a, currentOrder); 
    var B = parse(b, currentOrder); 
    if (A < B) { 
     return order === 'asc' ? -1 : 1; 
    } else if (A > B) { 
     return order === 'asc' ? 1 : -1; 
    } 
    } 
    return 0; 
}); 
+0

Большое спасибо. Он работает отлично. Однако возможно ли это и рекурсивно? – Ozil

+1

Конечно, просто рекурсия над 'i'. Или повторите процедуру через массив sortBy и '.llice (1)' каждый раз, чтобы получить копию без первого элемента. И не забывайте свой базовый случай! – Bergi

Смежные вопросы