Ninguna de estas respuestas es ideal como método de propósito general para usar varios campos en una clasificación. Todos los enfoques anteriores son ineficaces ya que requieren ordenar la matriz varias veces (lo que, en una lista lo suficientemente grande, podría ralentizar mucho las cosas) o generan grandes cantidades de objetos basura que la máquina virtual necesitará limpiar (y, en última instancia, ralentizar el programa abajo).
Aquí hay una solución que es rápida, eficiente, permite fácilmente la clasificación inversa y se puede utilizar con underscore
olodash
, o directamente conArray.sort
La parte más importante es el compositeComparator
método, que toma una matriz de funciones de comparación y devuelve una nueva función de comparación compuesta.
/**
* 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);
});
}
También necesitará una función de comparación para comparar los campos por los que desea ordenar. La naturalSort
función creará un comparador dado un campo en particular. Escribir un comparador para la clasificación inversa también es 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 el código hasta ahora es reutilizable y podría guardarse en el módulo de utilidad, por ejemplo)
A continuación, debe crear el comparador compuesto. Para nuestro ejemplo, se vería así:
var cmp = compositeComparator([naturalSort('roomNumber'), naturalSort('name')]);
Esto ordenará por número de habitación, seguido del nombre. Agregar criterios de clasificación adicionales es trivial y no afecta el rendimiento de la clasificación.
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);
Devuelve lo siguiente
[ { name: 'Chris', roomNumber: 1, bedNumber: 1 },
{ name: 'Lisa', roomNumber: 2, bedNumber: 2 },
{ name: 'Omar', roomNumber: 2, bedNumber: 1 },
{ name: 'John', roomNumber: 3, bedNumber: 1 } ]
La razón por la que prefiero este método es que permite una clasificación rápida en un número arbitrario de campos, no genera mucha basura ni realiza una concatenación de cadenas dentro de la clasificación y se puede usar fácilmente para que algunas columnas se clasifiquen al revés mientras que las columnas de orden usan natural ordenar.