Ни один из этих ответов не является идеальным в качестве универсального метода для использования нескольких полей при сортировке. Все вышеперечисленные подходы неэффективны, так как они либо требуют сортировки массива несколько раз (что в достаточно большом списке может сильно замедлить работу), либо генерируют огромное количество мусорных объектов, которые виртуальной машине нужно будет очистить (и, в конечном итоге, замедлить программа выключена).
Вот решение, которое является быстрым, эффективным, легко допускает обратную сортировку и может использоваться с underscore
или lodash
или напрямую сArray.sort
Самая важная часть - это compositeComparator
метод, который принимает массив функций компаратора и возвращает новую функцию составного компаратора.
/**
* Chains a comparator function to another comparator
* and returns the result of the first comparator, unless
* the first comparator returns 0, in which case the
* result of the second comparator is used.
*/
function makeChainedComparator(first, next) {
return function(a, b) {
var result = first(a, b);
if (result !== 0) return result;
return next(a, b);
}
}
/**
* Given an array of comparators, returns a new comparator with
* descending priority such that
* the next comparator will only be used if the precending on returned
* 0 (ie, found the two objects to be equal)
*
* Allows multiple sorts to be used simply. For example,
* sort by column a, then sort by column b, then sort by column c
*/
function compositeComparator(comparators) {
return comparators.reduceRight(function(memo, comparator) {
return makeChainedComparator(comparator, memo);
});
}
Вам также понадобится функция компаратора для сравнения полей, которые вы хотите отсортировать. naturalSort
Функция будет создать компаратор с учетом конкретной области. Написание компаратора для обратной сортировки тоже тривиально.
function naturalSort(field) {
return function(a, b) {
var c1 = a[field];
var c2 = b[field];
if (c1 > c2) return 1;
if (c1 < c2) return -1;
return 0;
}
}
(Весь код до сих пор можно использовать повторно и, например, можно сохранить в служебном модуле)
Далее вам нужно создать составной компаратор. В нашем примере это будет выглядеть так:
var cmp = compositeComparator([naturalSort('roomNumber'), naturalSort('name')]);
Это будет отсортировано по номеру комнаты, а затем по имени. Добавление дополнительных критериев сортировки тривиально и не влияет на производительность сортировки.
var patients = [
{name: 'John', roomNumber: 3, bedNumber: 1},
{name: 'Omar', roomNumber: 2, bedNumber: 1},
{name: 'Lisa', roomNumber: 2, bedNumber: 2},
{name: 'Chris', roomNumber: 1, bedNumber: 1},
];
// Sort using the composite
patients.sort(cmp);
console.log(patients);
Возвращает следующее
[ { name: 'Chris', roomNumber: 1, bedNumber: 1 },
{ name: 'Lisa', roomNumber: 2, bedNumber: 2 },
{ name: 'Omar', roomNumber: 2, bedNumber: 1 },
{ name: 'John', roomNumber: 3, bedNumber: 1 } ]
Причина, по которой я предпочитаю этот метод, заключается в том, что он позволяет выполнять быструю сортировку по произвольному количеству полей, не генерирует много мусора и не выполняет конкатенацию строк внутри сортировки и может легко использоваться, чтобы некоторые столбцы были отсортированы в обратном порядке, в то время как столбцы порядка используют естественный Сортировать.