Nenhuma dessas respostas é ideal como método de propósito geral para o uso de vários campos em uma classificação. Todas as abordagens acima são ineficientes, pois exigem a classificação da matriz várias vezes (o que, em uma lista grande o suficiente, pode tornar as coisas muito lentas) ou geram grandes quantidades de objetos de lixo que a VM precisará limpar (e, por fim, desacelerar o programa desativado).
Esta é uma solução que é rápida, eficiente, permite fácil classificação reversa e pode ser usada com underscore
ou lodash
, ou diretamente comArray.sort
A parte mais importante é o compositeComparator
método, que pega uma matriz de funções de comparador e retorna uma nova função de comparador composto.
/**
* 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);
});
}
Você também precisará de uma função de comparador para comparar os campos que deseja classificar. A naturalSort
função criará um comparador para um determinado campo. Escrever um comparador para classificação reversa também é trivial.
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;
}
}
(Todo o código até agora é reutilizável e pode ser mantido no módulo utilitário, por exemplo)
Em seguida, você precisa criar o comparador composto. Para nosso exemplo, seria assim:
var cmp = compositeComparator([naturalSort('roomNumber'), naturalSort('name')]);
Isso classificará pelo número do quarto, seguido pelo nome. Adicionar critérios de classificação adicionais é trivial e não afeta o desempenho da classificação.
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);
Retorna o seguinte
[ { name: 'Chris', roomNumber: 1, bedNumber: 1 },
{ name: 'Lisa', roomNumber: 2, bedNumber: 2 },
{ name: 'Omar', roomNumber: 2, bedNumber: 1 },
{ name: 'John', roomNumber: 3, bedNumber: 1 } ]
A razão pela qual eu prefiro este método é que ele permite uma classificação rápida em um número arbitrário de campos, não gera muito lixo ou executa concatenação de strings dentro da classificação e pode ser facilmente usado para que algumas colunas sejam classificadas de forma reversa enquanto as colunas de ordem usam natural ordenar.