ordenar - sort array javascript by key
Ordenar la matriz de objetos por valor de propiedad de cadena (30)
Clasificación (más) matrices complejas de objetos
Dado que probablemente encuentre estructuras de datos más complejas como esta matriz, expandiría la solución.
TL; DR
Son versiones más conectables basadas en la answer muy bonita de @ege-Özcan .
Problema
Encontré lo de abajo y no pude cambiarlo. Tampoco quise aplanar el objeto temporalmente. Tampoco quise utilizar el guión bajo / lodash, principalmente por motivos de rendimiento y la diversión para implementarlo yo mismo.
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
Gol
El objetivo es clasificarlo principalmente por People.Name.name
y, en segundo lugar, por People.Name.surname
Obstáculos
Ahora, en la solución base se usa la notación de corchetes para calcular las propiedades para ordenar dinámicamente. Sin embargo, aquí también tendríamos que construir dinámicamente la notación de corchetes, ya que uno esperaría que People[''Name.name'']
como People[''Name.name'']
funcionen, lo que no funciona.
Simplemente haciendo People[''Name''][''name'']
, por otro lado, es estático y solo te permite bajar el nivel n -ésimo.
Solución
La adición principal aquí será recorrer el árbol de objetos y determinar el valor de la última hoja, que debe especificar, así como cualquier hoja intermedia.
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
People.sort(dynamicMultiSort([''Name'',''name''], [''Name'', ''-surname'']));
// Results in...
// [ { Name: { name: ''AAA'', surname: ''ZZZ'' }, Middlename: ''Abrams'' },
// { Name: { name: ''Name'', surname: ''Surname'' }, Middlename: ''JJ'' },
// { Name: { name: ''Name'', surname: ''AAA'' }, Middlename: ''Wars'' } ]
// same logic as above, but strong deviation for dynamic properties
function dynamicSort(properties) {
var sortOrder = 1;
// determine sort order by checking sign of last element of array
if(properties[properties.length - 1][0] === "-") {
sortOrder = -1;
// Chop off sign
properties[properties.length - 1] = properties[properties.length - 1].substr(1);
}
return function (a,b) {
propertyOfA = recurseObjProp(a, properties)
propertyOfB = recurseObjProp(b, properties)
var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
return result * sortOrder;
};
}
/**
* Takes an object and recurses down the tree to a target leaf and returns it value
* @param {Object} root - Object to be traversed.
* @param {Array} leafs - Array of downwards traversal. To access the value: {parent:{ child: ''value''}} -> [''parent'',''child'']
* @param {Number} index - Must not be set, since it is implicit.
* @return {String|Number} The property, which is to be compared by sort.
*/
function recurseObjProp(root, leafs, index) {
index ? index : index = 0
var upper = root
// walk down one level
lower = upper[leafs[index]]
// Check if last leaf has been hit by having gone one step too far.
// If so, return result from last step.
if (!lower) {
return upper
}
// Else: recurse!
index++
// HINT: Bug was here, for not explicitly returning function
// https://stackoverflow.com/a/17528613/3580261
return recurseObjProp(lower, leafs, index)
}
/**
* Multi-sort your array by a set of properties
* @param {...Array} Arrays to access values in the form of: {parent:{ child: ''value''}} -> [''parent'',''child'']
* @return {Number} Number - number for sort algorithm
*/
function dynamicMultiSort() {
var args = Array.prototype.slice.call(arguments); // slight deviation to base
return function (a, b) {
var i = 0, result = 0, numberOfProperties = args.length;
// REVIEW: slightly verbose; maybe no way around because of `.sort`-''s nature
// Consider: `.forEach()`
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(args[i])(a, b);
i++;
}
return result;
}
}
Ejemplo
Ejemplo de trabajo en JSBin
Tengo una matriz de objetos JavaScript:
var objs = [
{ first_nom: ''Lazslo'', last_nom: ''Jamf'' },
{ first_nom: ''Pig'', last_nom: ''Bodine'' },
{ first_nom: ''Pirate'', last_nom: ''Prentice'' }
];
¿Cómo puedo ordenarlos por el valor de last_nom
en JavaScript?
Sé de sort(a,b)
, pero eso solo parece funcionar en cadenas y números. ¿Necesito agregar un método toString()
a mis objetos?
A partir de 2018 existe una solución mucho más corta y elegante. Solo usa. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… .
Ejemplo:
var items = [
{ name: ''Edward'', value: 21 },
{ name: ''Sharpe'', value: 37 },
{ name: ''And'', value: 45 },
{ name: ''The'', value: -12 },
{ name: ''Magnetic'', value: 13 },
{ name: ''Zeros'', value: 37 }
];
// sort by value
items.sort(function (a, b) {
return a.value - b.value;
});
Combinando la solución dinámica de Ege con la idea de Vinay, obtiene una solución robusta y agradable:
Array.prototype.sortBy = function() {
function _sortByAttr(attr) {
var sortOrder = 1;
if (attr[0] == "-") {
sortOrder = -1;
attr = attr.substr(1);
}
return function(a, b) {
var result = (a[attr] < b[attr]) ? -1 : (a[attr] > b[attr]) ? 1 : 0;
return result * sortOrder;
}
}
function _getSortFunc() {
if (arguments.length == 0) {
throw "Zero length arguments not allowed for Array.sortBy()";
}
var args = arguments;
return function(a, b) {
for (var result = 0, i = 0; result == 0 && i < args.length; i++) {
result = _sortByAttr(args[i])(a, b);
}
return result;
}
}
return this.sort(_getSortFunc.apply(null, arguments));
}
Uso:
// Utility for printing objects
Array.prototype.print = function(title) {
console.log("************************************************************************");
console.log("**** "+title);
console.log("************************************************************************");
for (var i = 0; i < this.length; i++) {
console.log("Name: "+this[i].FirstName, this[i].LastName, "Age: "+this[i].Age);
}
}
// Setup sample data
var arrObj = [
{FirstName: "Zach", LastName: "Emergency", Age: 35},
{FirstName: "Nancy", LastName: "Nurse", Age: 27},
{FirstName: "Ethel", LastName: "Emergency", Age: 42},
{FirstName: "Nina", LastName: "Nurse", Age: 48},
{FirstName: "Anthony", LastName: "Emergency", Age: 44},
{FirstName: "Nina", LastName: "Nurse", Age: 32},
{FirstName: "Ed", LastName: "Emergency", Age: 28},
{FirstName: "Peter", LastName: "Physician", Age: 58},
{FirstName: "Al", LastName: "Emergency", Age: 51},
{FirstName: "Ruth", LastName: "Registration", Age: 62},
{FirstName: "Ed", LastName: "Emergency", Age: 38},
{FirstName: "Tammy", LastName: "Triage", Age: 29},
{FirstName: "Alan", LastName: "Emergency", Age: 60},
{FirstName: "Nina", LastName: "Nurse", Age: 54}
];
//Unit Tests
arrObj.sortBy("LastName").print("LastName Ascending");
arrObj.sortBy("-LastName").print("LastName Descending");
arrObj.sortBy("LastName", "FirstName", "-Age").print("LastName Ascending, FirstName Ascending, Age Descending");
arrObj.sortBy("-FirstName", "Age").print("FirstName Descending, Age Ascending");
arrObj.sortBy("-Age").print("Age Descending");
Ejemplo de uso:
objs.sort(sortBy(''last_nom''));
Guión:
/**
* @description
* Returns a function which will sort an
* array of objects by the given key.
*
* @param {String} key
* @param {Boolean} reverse
* @return {Function}
*/
function sortBy(key, reverse) {
// Move smaller items towards the front
// or back of the array depending on if
// we want to sort the array in reverse
// order or not.
var moveSmaller = reverse ? 1 : -1;
// Move larger items towards the front
// or back of the array depending on if
// we want to sort the array in reverse
// order or not.
var moveLarger = reverse ? -1 : 1;
/**
* @param {*} a
* @param {*} b
* @return {Number}
*/
return function(a, b) {
if (a[key] < b[key]) {
return moveSmaller;
}
if (a[key] > b[key]) {
return moveLarger;
}
return 0;
};
}
En ES6 / ES2015 o posterior puedes hacer esto:
objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));
En lugar de usar una función de comparación personalizada, también puede crear un tipo de objeto con el método toString()
(que es invocado por la función de comparación predeterminada):
function Person(firstName, lastName) {
this.firtName = firstName;
this.lastName = lastName;
}
Person.prototype.toString = function() {
return this.lastName + '', '' + this.firstName;
}
var persons = [ new Person(''Lazslo'', ''Jamf''), ...]
persons.sort();
Es bastante fácil escribir tu propia función de comparación:
function compare(a,b) {
if (a.last_nom < b.last_nom)
return -1;
if (a.last_nom > b.last_nom)
return 1;
return 0;
}
objs.sort(compare);
O en línea (c / o Marco Demaio):
objs.sort((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0));
Hay muchas respuestas buenas aquí, pero me gustaría señalar que se pueden extender muy simplemente para lograr una clasificación mucho más compleja. Lo único que tienes que hacer es usar el operador OR para encadenar funciones de comparación como esta:
objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )
Donde fn1
, fn1
, ... son las funciones de ordenación que devuelven [-1,0,1]. Esto da como resultado "ordenar por fn1", "ordenar por fn2", que es prácticamente igual a ORDER BY en SQL.
Esta solución se basa en el comportamiento de ||
operador que evalúa la primera expresión evaluada que se puede convertir en verdadero .
La forma más simple tiene solo una función en línea como esta:
// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )
Teniendo dos pasos con last_nom
, el first_nom
orden de clasificación se vería así:
// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) ||
a.first_nom.localeCompare(b.first_nom) )
Una función de comparación genérica podría ser algo como esto:
// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])
Esta función podría ampliarse para admitir campos numéricos, sensibilidad de caso, tipos de datos arbitrarios, etc.
Puedes usarlos encadenándolos por orden de prioridad:
// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
El punto aquí es que el JavaScript puro con enfoque funcional puede llevarlo lejos sin bibliotecas externas o código complejo. También es muy efectivo, ya que no se debe hacer un análisis de cadena.
No entiendo por qué la gente lo hace tan complicado:
objs.sort(function(a, b){
return a.last_nom > b.last_nom;
});
Para motores más estrictos:
objs.sort(function(a, b){
return a.last_nom == b.last_nom ? 0 : +(a.last_nom > b.last_nom) || -1;
});
Cambie el operador para ordenarlo por orden alfabético inverso.
No he visto este enfoque en particular sugerido, así que aquí hay un método de comparación conciso que me gusta usar que funciona tanto para la string
como para el number
:
const objs = [
{ first_nom: ''Lazslo'', last_nom: ''Jamf'' },
{ first_nom: ''Pig'', last_nom: ''Bodine'' },
{ first_nom: ''Pirate'', last_nom: ''Prentice'' }
];
const sortBy = fn => (a, b) => -(fn(a) < fn(b)) || +(fn(a) > fn(b))
const getLastName = o => o.last_nom
const sortByLastName = sortBy(getLastName)
objs.sort(sortByLastName)
console.log(objs.map(getLastName))
Aquí hay una explicación de sortBy()
:
sortBy()
acepta un fn
que selecciona qué valor de un objeto para usar como comparación, y devuelve una función que se puede pasar directamente a Array.prototype.sort()
.En este ejemplo, estamos usando o.last_nom
el valor de comparación, por lo que cada vez que recibimos dos objetos a través de Array.prototype.sort()
, como
{ first_nom: ''Lazslo'', last_nom: ''Jamf'' }
y
{ first_nom: ''Pig'', last_nom: ''Bodine'' }
usamos
(a, b) => -(fn(a) < fn(b)) || +(fn(a) > fn(b))
para compararlos
Recordando eso fn = o => o.last_nom
, podemos expandir la función de comparación al equivalente
(a, b) => -(a.last_nom < b.last_nom) || +(a.last_nom > b.last_nom)
El ||
operador lógico OR tiene una funcionalidad de cortocircuito que es muy útil aquí. Debido a cómo funciona, el cuerpo de la función anterior significa
if (a.last_nom < b.last_nom) return -1
return +(a.last_nom > b.last_nom)
Entonces, si a < b
regresamos -1
, de lo contrario, si a > b
luego regresamos +1
, pero si a == b
, entonces a < b
y a > b
somos falsos, entonces regresa +0
.
Como un bono adicional, aquí está el equivalente en ECMAScript 5.1 sin funciones de flecha, que desafortunadamente no es tan conciso:
var objs = [
{ first_nom: ''Lazslo'', last_nom: ''Jamf'' },
{ first_nom: ''Pig'', last_nom: ''Bodine'' },
{ first_nom: ''Pirate'', last_nom: ''Prentice'' }
];
var sortBy = function (fn) {
return function (a, b) {
return -(fn(a) < fn(b)) || +(fn(a) > fn(b))
}
}
var getLastName = function (o) { return o.last_nom }
var sortByLastName = sortBy(getLastName)
objs.sort(sortByLastName)
console.log(objs.map(getLastName))
Puedes usar
Manera más fácil: Lodash
( https://lodash.com/docs/4.17.10#orderBy )
Este método es como _.sortBy, excepto que permite especificar los órdenes de clasificación de las iteraciones para ordenar. Si las órdenes no se especifican, todos los valores se ordenan en orden ascendente. De lo contrario, especifique un orden de "desc" para descendente o "asc" para el orden ascendente de los valores correspondientes.
Argumentos
collection (Array | Object): la colección para iterar sobre. [iteratees = [_. identity]] (Array [] | Function [] | Object [] | string []): el iterar para ordenar. [órdenes] (cadena []): los ordenamientos de iteraciones.
Devoluciones
(Array): devuelve la nueva matriz ordenada.
var _ = require(''lodash'');
var homes = [
{"h_id":"3",
"city":"Dallas",
"state":"TX",
"zip":"75201",
"price":"162500"},
{"h_id":"4",
"city":"Bevery Hills",
"state":"CA",
"zip":"90210",
"price":"319250"},
{"h_id":"6",
"city":"Dallas",
"state":"TX",
"zip":"75000",
"price":"556699"},
{"h_id":"5",
"city":"New York",
"state":"NY",
"zip":"00010",
"price":"962500"}
];
_.orderBy(homes, [''city'', ''state'', ''zip''], [''asc'', ''desc'', ''asc'']);
Sé que esta pregunta es demasiado antigua, pero no vi ninguna implementación similar a la mía.
Esta versión está basada en el lenguaje de transformación de Schwartz .
function sortByAttribute(array, ...attrs) {
// generate an array of predicate-objects contains
// property getter, and descending indicator
let predicates = attrs.map(pred => {
let descending = pred.charAt(0) === ''-'' ? -1 : 1;
pred = pred.replace(/^-/, '''');
return {
getter: o => o[pred],
descend: descending
};
});
// schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
return array.map(item => {
return {
src: item,
compareValues: predicates.map(predicate => predicate.getter(item))
};
})
.sort((o1, o2) => {
let i = -1, result = 0;
while (++i < predicates.length) {
if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
if (result *= predicates[i].descend) break;
}
return result;
})
.map(item => item.src);
}
Aquí hay un ejemplo de cómo usarlo:
let games = [
{ name: ''Pako'', rating: 4.21 },
{ name: ''Hill Climb Racing'', rating: 3.88 },
{ name: ''Angry Birds Space'', rating: 3.88 },
{ name: ''Badland'', rating: 4.33 }
];
// sort by one attribute
console.log(sortByAttribute(games, ''name''));
// sort by mupltiple attributes
console.log(sortByAttribute(games, ''-rating'', ''name''));
Si tiene apellidos duplicados, puede ordenarlos por nombre
obj.sort(function(a,b){
if(a.last_nom< b.last_nom) return -1;
if(a.last_nom >b.last_nom) return 1;
if(a.first_nom< b.first_nom) return -1;
if(a.first_nom >b.first_nom) return 1;
return 0;
});
Siguiendo su ejemplo, necesita ordenar por dos campos (apellido, primer nombre), en lugar de uno. Puede usar la biblioteca Alasql para hacer este tipo en una línea:
var res = alasql(''SELECT * FROM ? ORDER BY last_nom, first_nom'',[objs]);
Prueba este ejemplo en jsFiddle .
Solución simple y rápida a este problema usando la herencia del prototipo:
Array.prototype.sortBy = function(p) {
return this.slice(0).sort(function(a,b) {
return (a[p] > b[p]) ? 1 : (a[p] < b[p]) ? -1 : 0;
});
}
Ejemplo / Uso
objs = [{age:44,name:''vinay''},{age:24,name:''deepak''},{age:74,name:''suresh''}];
objs.sortBy(''age'');
// Returns
// [{"age":24,"name":"deepak"},{"age":44,"name":"vinay"},{"age":74,"name":"suresh"}]
objs.sortBy(''name'');
// Returns
// [{"age":24,"name":"deepak"},{"age":74,"name":"suresh"},{"age":44,"name":"vinay"}]
Actualización: ya no modifica la matriz original.
También puede crear una función de ordenación dinámica que ordene los objetos por el valor que pase:
function dynamicSort(property) {
var sortOrder = 1;
if(property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a,b) {
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
Así que puedes tener una matriz de objetos como este:
var People = [
{Name: "Name", Surname: "Surname"},
{Name:"AAA", Surname:"ZZZ"},
{Name: "Name", Surname: "AAA"}
];
... y funcionará cuando lo hagas:
People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));
En realidad esto ya responde a la pregunta. La parte inferior está escrita porque muchas personas se contactaron conmigo, quejándose de que no funciona con múltiples parámetros .
Parámetros múltiples
Puede utilizar la siguiente función para generar funciones de clasificación con múltiples parámetros de clasificación.
function dynamicSortMultiple() {
/*
* save the arguments object as it will be overwritten
* note that arguments object is an array-like object
* consisting of the names of the properties to sort by
*/
var props = arguments;
return function (obj1, obj2) {
var i = 0, result = 0, numberOfProperties = props.length;
/* try getting a different result from 0 (equal)
* as long as we have extra properties to compare
*/
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(props[i])(obj1, obj2);
i++;
}
return result;
}
}
Lo que te permitiría hacer algo como esto:
People.sort(dynamicSortMultiple("Name", "-Surname"));
Añadiéndolo al prototipo
(La implementación que está justo debajo está inspirada en la answer de Mike R )
No recomendaría cambiar un prototipo de objeto nativo, pero solo para dar un ejemplo para que pueda implementarlo en sus propios objetos (para los entornos que lo admiten, también puede usar Object.defineProperty como se muestra en la siguiente sección, que al menos no tiene el efecto secundario negativo de ser enumerable, como se describe en la última parte)
La implementación de prototipos sería algo como lo siguiente ( Aquí hay un ejemplo de trabajo ):
//Don''t just copy-paste this code. You will break the "for-in" loops
!function() {
function _dynamicSortMultiple(attr) {
/* dynamicSortMultiple function body comes here */
}
function _dynamicSort(property) {
/* dynamicSort function body comes here */
}
Array.prototype.sortBy = function() {
return this.sort(_dynamicSortMultiple.apply(null, arguments));
}
}();
La forma "OK" de agregarlo al prototipo
Si está apuntando a IE v9.0 y más, entonces, como mencioné anteriormente, use Object.defineProperty como este ( ejemplo funcional ):
//Won''t work below IE9, but totally safe otherwise
!function() {
function _dynamicSortMultiple(attr) {
/* dynamicSortMultiple function body comes here */
}
function _dynamicSort(property) {
/* dynamicSort function body comes here */
}
Object.defineProperty(Array.prototype, "sortBy", {
enumerable: false,
writable: true,
value: function() {
return this.sort(_dynamicSortMultiple.apply(null, arguments));
}
});
}();
Esto puede ser un compromiso aceptable hasta que llegue el operador de vinculación.
Toda esa diversión prototipo lo habilita:
People.sortBy("Name", "-Surname");
Deberías leer esto
Si usa el método de acceso directo de prototipo (Object.defineProperty está bien) y el otro código no comprueba hasOwnProperty , ¡los gatitos mueren! Ok, para ser honesto, ningún gatito le hace daño realmente, pero probablemente las cosas se romperán y todos los demás desarrolladores de tu equipo te odiarán:
¿Ves ese último "SortBy"? Sí. No es genial Use Object.defineProperty donde pueda, y deje el Array.prototype solo de lo contrario.
Tengo un código que me funciona:
arr.sort((a, b) => a.name > b.name)
ACTUALIZACIÓN: No funciona siempre, por lo que no es correcto :(
Una forma sencilla:
objs.sort(function(a,b) {
return b.last_nom.toLowerCase() < a.last_nom.toLowerCase();
});
Vea que ''.toLowerCase()''
es necesario para evitar errores al comparar cadenas.
Una opción más:
var someArray = [...];
function generateSortFn(prop, reverse) {
return function (a, b) {
if (a[prop] < b[prop]) return reverse ? 1 : -1;
if (a[prop] > b[prop]) return reverse ? -1 : 1;
return 0;
};
}
someArray.sort(generateSortFn(''name'', true));
ordena el ascenso por defecto.
parámetros adicionales de desc para el código Ege Özcan
function dynamicSort(property, desc) {
if (desc) {
return function (a, b) {
return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
}
}
return function (a, b) {
return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
}
}
Usa subrayado, es pequeño e impresionante ...
sortBy_.sortBy (lista, iterador, [contexto]) Devuelve una copia ordenada de la lista, clasificada en orden ascendente por los resultados de la ejecución de cada valor a través del iterador. El iterador también puede ser el nombre de la cadena de la propiedad por la que se ordena (por ejemplo, la longitud).
var objs = [
{ first_nom: ''Lazslo'',last_nom: ''Jamf'' },
{ first_nom: ''Pig'', last_nom: ''Bodine'' },
{ first_nom: ''Pirate'', last_nom: ''Prentice'' }
];
var sortedObjs = _.sortBy( objs, ''first_nom'' );
Lodash.js (superconjunto de Underscore.js )
Es bueno no agregar un marco para cada pieza simple de lógica, pero confiar en un marco de utilidad bien probado, acelerar el desarrollo y reducir la cantidad de errores escritos no es una vergüenza.
Lodash produce código muy limpio y promueve un estilo de programación más funcional , lo que resulta en menos errores. En un vistazo, queda claro cuál es la intención del código.
El problema de OP se puede resolver simplemente como:
const sortedObjs = _.sortBy(objs, ''last_nom'');
¿Más información? Por ejemplo, tenemos el siguiente objeto anidado:
const users = [
{ ''user'': {''name'':''fred'', ''age'': 48}},
{ ''user'': {''name'':''barney'', ''age'': 36 }},
{ ''user'': {''name'':''wilma''}},
{ ''user'': {''name'':''betty'', ''age'': 32}}
];
Ahora podemos usar _.property shorthand user.age
para especificar la ruta a la propiedad que debe coincidir. Ordenaremos los objetos de usuario por la propiedad de edad anidada. Sí, permite la coincidencia de propiedades anidadas!
const sortedObjs = _.sortBy(users, [''user.age'']);
¿Quieres revertirlo? No hay problema. Utilice _.reverse .
const sortedObjs = _.reverse(_.sortBy(users, [''user.age'']));
¿Quieres combinar ambos usando Chaining lugar?
const sortedObjs = _.chain(users).sortBy(''user.age'').reverse().value();
Dado el ejemplo original:
var objs = [
{ first_nom: ''Lazslo'', last_nom: ''Jamf'' },
{ first_nom: ''Pig'', last_nom: ''Bodine'' },
{ first_nom: ''Pirate'', last_nom: ''Prentice'' }
];
Ordenar por múltiples campos:
objs.sort(function(left, right) {
var last_nom_order = left.last_nom.localeCompare(right.last_nom);
var first_nom_order = left.first_nom.localeCompare(right.first_nom);
return last_nom_order || first_nom_order;
});
Notas
-
a.localeCompare(b)
está universalmente compatible y vuelve -1,0,1 sia<b
,a==b
,a>b
respectivamente. -
||
En la última línea dalast_nom
prioridad a másfirst_nom
. - La resta funciona en campos numéricos:
var age_order = left.age - right.age;
- Negar para revertir el orden,
return -last_nom_order || -first_nom_order || -age_order;
Es posible que deba convertirlos a minúsculas para evitar confusiones.
objs.sort(function (a,b) {
var nameA=a.last_nom.toLowerCase(), nameB=b.last_nom.toLowerCase()
if (nameA < nameB)
return -1;
if (nameA > nameB)
return 1;
return 0; //no sorting
})
Usando lodash o subrayado, es un pedazo de pastel
> const sortedList = _.orderBy(objs, [last_nom], [asc]); // asc or desc
Utilizando Ramda,
npm instalar ramda
import R from ''ramda''
var objs = [
{ first_nom: ''Lazslo'', last_nom: ''Jamf'' },
{ first_nom: ''Pig'', last_nom: ''Bodine'' },
{ first_nom: ''Pirate'', last_nom: ''Prentice'' }
];
var ascendingSortedObjs = R.sortBy(R.prop(''last_nom''), objs)
var descendingSortedObjs = R.reverse(ascendingSortedObjs)
Acabo de mejorar el ordenamiento dinámico de Ege Özcan para sumergirse profundamente en los objetos. Si Data se parece a esto:
obj = [
{
a: { a: 1, b: 2, c: 3 },
b: { a: 4, b: 5, c: 6 }
},
{
a: { a: 3, b: 2, c: 1 },
b: { a: 6, b: 5, c: 4 }
}];
y si desea clasificarlo en una propiedad, creo que mi mejora es muy útil. Añado nuevas funcionalidades a objetos como este:
Object.defineProperty(Object.prototype, ''deepVal'', {
enumerable: false,
writable: true,
value: function (propertyChain) {
var levels = propertyChain.split(''.'');
parent = this;
for (var i = 0; i < levels.length; i++) {
if (!parent[levels[i]])
return undefined;
parent = parent[levels[i]];
}
return parent;
}
});
y cambió la función de retorno de _dynamicSort :
return function (a,b) {
var result = ((a.deepVal(property) > b.deepVal(property)) - (a.deepVal(property) < b.deepVal(property)));
return result * sortOrder;
}
Y ahora puedes ordenar por aa de esta manera:
obj.sortBy(''a.a'');
Ver Secuencias de comandos completas en JSFiddle
Este es un problema simple, no sé por qué las personas tienen una solución tan compleja.
Una función de clasificación simple (basada en un algoritmo de clasificación rápida ):
function sortObjectsArray(objectsArray, sortKey)
{
// Quick Sort:
var retVal;
if (1 < objectsArray.length)
{
var pivotIndex = Math.floor((objectsArray.length - 1) / 2); // middle index
var pivotItem = objectsArray[pivotIndex]; // value in the middle index
var less = [], more = [];
objectsArray.splice(pivotIndex, 1); // remove the item in the pivot position
objectsArray.forEach(function(value, index, array)
{
value[sortKey] <= pivotItem[sortKey] ? // compare the ''sortKey'' proiperty
less.push(value) :
more.push(value) ;
});
retVal = sortObjectsArray(less, sortKey).concat([pivotItem], sortObjectsArray(more, sortKey));
}
else
{
retVal = objectsArray;
}
return retVal;
}
Ejemplo de uso:
var myArr =
[
{ val: ''x'', idx: 3 },
{ val: ''y'', idx: 2 },
{ val: ''z'', idx: 5 },
];
myArr = sortObjectsArray(myArr, ''idx'');
function compare(propName) {
return function(a,b) {
if (a[propName] < b[propName])
return -1;
if (a[propName] > b[propName])
return 1;
return 0;
};
}
objs.sort(compare("last_nom"));
objs.sort(function(a,b){return b.last_nom>a.last_nom})