Ordenar matriz por nombre (alfabéticamente) en Javascript

647

Obtuve una matriz (ver abajo para un objeto en la matriz) que necesito ordenar por nombre usando JavaScript. ¿Cómo puedo hacerlo?

var user = {
   bio: null,
   email:  "[email protected]",
   firstname: "Anna",
   id: 318,
   lastAvatar: null,
   lastMessage: null,
   lastname: "Nickson",
   nickname: "anny"
};
Jonathan Clark
fuente
posible duplicado de Sort JavaScript array of Objects
Felix Kling

Respuestas:

1068

Supongamos que tiene una matriz users. Puede usar users.sorty pasar una función que tome dos argumentos y compararlos (comparador)

Debería volver

  • algo negativo si el primer argumento es menor que el segundo (debe colocarse antes del segundo en la matriz resultante)
  • algo positivo si el primer argumento es mayor (debe colocarse después del segundo)
  • 0 si esos dos elementos son iguales.

En nuestro caso si dos elementos son ay bqueremos comparar a.firstnameyb.firstname

Ejemplo:

users.sort(function(a, b){
    if(a.firstname < b.firstname) { return -1; }
    if(a.firstname > b.firstname) { return 1; }
    return 0;
})

Este código va a funcionar con cualquier tipo.

Tenga en cuenta que en la "vida real" ™ a menudo desea ignorar mayúsculas y minúsculas, clasificar correctamente los signos diacríticos, símbolos extraños como ß, etc. cuando compara cadenas, por lo que es posible que desee utilizarlas localeCompare. Ver otras respuestas para mayor claridad.

RiaD
fuente
55
Friggin increíble ... Estoy ordenando una lista de nodos por id ... funciona como un encanto. Gracias una tonelada!
Cody
74
Para aquellos que vienen en una fecha posterior, la respuesta de Mrchief es mejor porque no distingue entre mayúsculas y minúsculas.
mlienau 01 de
25
@mlienau, no lo llamaría mejor o peor. Es solo otro
RiaD el
19
@RiaD lo suficientemente justo. Simplemente no puedo pensar en muchos casos de ordenar alfabéticamente los elementos, incluida la carcasa, donde 'Zebra' aparece en la lista antes de 'apple', sería muy útil.
mlienau
15
Este código solo funcionará en países de habla inglesa. En otros países, debería usar la respuesta de ovunccetina conlocaleCompare .
Spoike
546

¡El código más corto posible con ES6!

users.sort((a, b) => a.firstname.localeCompare(b.firstname))

¡El soporte básico String.prototype.localeCompare () es universal!

Nachiketha
fuente
27
Con mucho, la mejor respuesta si vives en 2017
nathanbirrell
52
La mejor respuesta también si vives en 2018;)
Simone
49
Probablemente sea la mejor respuesta para 2019 también.
Ahmad Maleki
24
2020 tal vez? o naaa?
kspearrin
15
Ah hombre, en 2030 la tierra se inunda y esto solo funciona en las montañas.
Starfs
343

Algo como esto:

array.sort(function(a, b){
 var nameA=a.name.toLowerCase(), nameB=b.name.toLowerCase();
 if (nameA < nameB) //sort string ascending
  return -1;
 if (nameA > nameB)
  return 1;
 return 0; //default return value (no sorting)
});
Mrchief
fuente
43
Cuando ordenar cadenas 'toLowerCase ()' es muy importante, las letras mayúsculas pueden afectar su clasificación.
MarzSocks
3
En caso de que alguien más se pregunte qué impacto tiene toLowerCase, no es mucho:'a'>'A' //true 'z'>'a' //true 'A'>'z' //false
SimplGy
14
@SimplGy Yo diría que su impacto es un poco más de lo que le estás dando crédito. Por ejemplo, como se indica en los comentarios a la respuesta aceptada, es importante saber si su función de clasificación clasificará la cadena 'Zebra'más alta que la cadena 'apple', lo que hará si no utiliza la función .toLowerCase().
PrinceTyke
1
@PrinceTyke, sí, es un buen caso, hombre. 'Z' < 'a' // truey'z' < 'a' // false
SimplGy
2
Todos los puntos válidos y yo diría que la clasificación es siempre un tipo de "depende". Si está ordenando por nombres, la distinción entre mayúsculas y minúsculas puede no importar. En otros casos podría ser. De todos modos, creo que adoptar la situación específica de uno no es difícil una vez que se tiene la idea central.
Mrchief
336

Si las cadenas comparadas contienen caracteres unicode, puede usar la localeComparefunción de Stringclase como la siguiente:

users.sort(function(a,b){
    return a.firstname.localeCompare(b.firstname);
})
ovunccetina
fuente
3
String.localeCompare no es compatible con Safari e IE <11 :)
CORSAIR
13
@CORSAIR es compatible, es solo el segundo y tercer parámetro que no son compatibles.
Codler
66
@CORSAIR, el uso en el ejemplo es compatible con todos los principales navegadores IE: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . LocaleCompare también tiene en cuenta la capitalización, por lo que creo que esta implementación debería considerarse la mejor práctica.
Matt Jensen
99
users.sort ((a, b) => a.firstname.localeCompare (b.firstname)) // ¡Versión corta y dulce de ES6!
Nachiketha
44
tanques hermano en uso ES6users.sort((a, b) => a.name.localeCompare(b.name))
Mohmmad Ebrahimi Aval
32

Bonito y pequeño ES6 one liner:

users.sort((a, b) => a.firstname !== b.firstname ? a.firstname < b.firstname ? -1 : 1 : 0);
Sam Logan
fuente
2
Este está incompleto ya que no maneja valores iguales correctamente.
Karl-Johan Sjögren
1
Por supuesto, gracias por detectar eso, he agregado un cheque para los valores coincidentes
Sam Logan
no está mal que supongo que si realmente lo quieres todo en una línea, ternarios anidados resultar confuso para facilitar la lectura, aunque
russter
24

Podemos usar localeCompare pero también debemos verificar las claves para los valores de falsey

El siguiente código no funcionará si falta una entrada en lname.

obj.sort((a, b) => a.lname.localeCompare(b.lname))

Por lo tanto, debemos verificar el valor de falsey como se muestra a continuación

let obj=[
{name:'john',lname:'doe',address:'Alaska'},
{name:'tom',lname:'hopes',address:'California'},
{name:'harry',address:'Texas'}
]
let field='lname';
console.log(obj.sort((a, b) => (a[field] || "").toString().localeCompare((b[field] || "").toString())));

O

podemos usar lodash, es muy simple. Detectará los valores devueltos, es decir, ya sea número o cadena, y hará la clasificación en consecuencia.

import sortBy from 'lodash/sortBy';
sortBy(obj,'name')

https://lodash.com/docs/4.17.5#sortBy

sumitir
fuente
2
¡Lodash es bastante ordenado! No había oído hablar de eso antes. ¡Funciona genial!
Derk Jan Speelman
15

underscorejs ofrece la muy buena función _.sortBy:

_.sortBy([{a:1},{a:3},{a:2}], "a")

o puede usar una función de clasificación personalizada:

_.sortBy([{a:"b"},{a:"c"},{a:"a"}], function(i) {return i.a.toLowerCase()})
Peter T.
fuente
2
El segundo ejemplo implica la devolución de cadenas. ¿ sortByDetecta que los valores devueltos son cadenas y, por lo tanto, realiza una clasificación alfabética? Gracias
superjos
12

En caso de que estemos clasificando nombres o algo con caracteres especiales, como ñ o áéíóú (comunes en español), podríamos usar los parámetros locales ( es para español en este caso) y opciones como esta:

let user = [{'firstname': 'Az'},{'firstname': 'Áb'},{'firstname':'ay'},{'firstname': 'Ña'},{'firstname': 'Nz'},{'firstname': 'ny'}];


user.sort((a, b) => a.firstname.localeCompare(b.firstname, 'es', {sensitivity: 'base'}))


console.log(user)

Las opciones locales oficiales se pueden encontrar aquí en iana , es (español), de (alemán), fr (francés). Acerca de la base de sensibilidad significa:

Solo las cadenas que difieren en letras base se comparan como desiguales. Ejemplos: a ≠ b, a = á, a = A.

Emeeus
fuente
8

Básicamente, puede ordenar las matrices con el método de clasificación, pero si desea ordenar los objetos, debe pasar la función para ordenar el método de la matriz, por lo que le daré un ejemplo usando su matriz

user = [{
bio: "<null>",
email: "[email protected]",
firstname: 'Anna',
id: 318,
"last_avatar": "<null>",
"last_message": "<null>",
lastname: 'Nickson',
nickname: 'anny'
},
{
bio: "<null>",
email: "[email protected]",
firstname: 'Senad',
id: 318,
"last_avatar": "<null>",
"last_message": "<null>",
lastname: 'Nickson',
nickname: 'anny'
},
{
bio: "<null>",
email: "[email protected]",
firstname: 'Muhamed',
id: 318,
"last_avatar": "<null>",
"last_message": "<null>",
lastname: 'Nickson',
nickname: 'anny'
}];

var ar = user.sort(function(a, b)
{
  var nA = a.firstname.toLowerCase();
  var nB = b.firstname.toLowerCase();

  if(nA < nB)
    return -1;
  else if(nA > nB)
    return 1;
 return 0;
});
Senad Meškin
fuente
¿Por qué devolver 0 al final?
Nobita
=, cuando las cuerdas son iguales
Senad Meškin
pero en ese caso, ¿no debería elseser eliminado? De lo contrario, eso return 0nunca se leerá
Nobita
2
eso no es "más", es "más si"
Senad Meškin
8

Inspirado en esta respuesta,

users.sort((a,b) => (a.firstname  - b.firstname));
Isuru Siriwardana
fuente
8

Una notación más compacta:

user.sort(function(a, b){
    return a.firstname === b.firstname ? 0 : a.firstname < b.firstname ? -1 : 1;
})
James Andrews
fuente
es más compacto pero viola su contrato: sign(f(a, b)) =-sign(f(b, a))(para a = b)
RiaD
3
el retorno a.firstname == b.firstnamedebe usarse ===para completar
2015
6

También para ambos tipos, asec y desc, puede usar esto: supongamos que tenemos una variable SortType que especifica la clasificación ascendente o descendente que desee:

 users.sort(function(a,b){
            return   sortType==="asc"? a.firstName.localeCompare( b.firstName): -( a.firstName.localeCompare(  b.firstName));
        })
ghazaleh javaheri
fuente
5

Una función generalizada se puede escribir como a continuación

    function getSortedData(data, prop, isAsc) {
        return data.sort((a, b) => (a[prop] < b[prop] ? -1 : 1) * (isAsc ? 1 : -1));
   }

puedes pasar los siguientes parámetros

  1. Los datos que quieres ordenar
  2. La propiedad en los datos por debe ser ordenada
  3. El último parámetro es de tipo booleano. Comprueba si quieres ordenar por ascendente o descendente
Santosh
fuente
4

tratar

users.sort((a,b)=> (a.firstname>b.firstname)*2-1)

Kamil Kiełczewski
fuente
2
la función de clasificación debería devolver -1,0,1. este solo devuelve -1,1.
Radu Luncasu
@RaduLuncasu: ¿puede proporcionar datos de prueba (matriz de usuarios) que muestren que la solución anterior da un resultado incorrecto? (que yo sepa, perder cero no es problema)
Kamil Kiełczewski
Si compareFunction (a, b) devuelve 0, deje a y b sin cambios entre sí, pero ordenados con respecto a todos los elementos diferentes.
Radu Luncasu
@RaduLuncasu está bien, pero esa información no significa que cero sea obligatorio. La mejor manera de mostrarlo es preparar datos que no funcionan, pero hasta donde sé, esto es imposible, por ejemplo[9,8,7,6,5,1,2,3].sort((a,b) => a<b ? -1 : 1)
Kamil Kiełczewski
3

Puedes usar esto para objetos

transform(array: any[], field: string): any[] {
return array.sort((a, b) => a[field].toLowerCase() !== b[field].toLowerCase() ? a[field].toLowerCase() < b[field].toLowerCase() ? -1 : 1 : 0);}
Andre Coetzee
fuente
2

en palabras simples, puedes usar este método

users.sort(function(a,b){return a.firstname < b.firstname ? -1 : 1});
FarukT
fuente
1

Puede usar el método de matriz incorporado - sort. Este método toma un método de devolución de llamada como parámetro



    // custom sort function to be passed as param/callback to the Array's sort method
    function myCustomSort(a, b) {
        return (a.toLowerCase() > b.toLowerCase()) ? 1 : -1;
    }

    // Actual method to be called by entity that needs sorting feature
    function sortStrings() {
        var op = Array.prototype.sort.call(arguments, myCustomSort);
    }

    // Testing the implementation
    var sortedArray = sortStrings("Burger", "Mayo1", "Pizza", "boxes", "Apples", "Mayo");
    console.log(sortedArray); //["Apples", "boxes", "Burger", "Mayo", "Mayo1", "Pizza"]


Puntos clave a tener en cuenta para comprender este código.

  1. El método personalizado, en este caso, myCustomSort debería devolver +1 o -1 para cada comparación de par de elementos (de la matriz de entrada).
  2. Utilice toLowerCase()/ toUpperCase()en el método de devolución de llamada de clasificación personalizado para que la diferencia de mayúsculas y minúsculas no afecte a la corrección del proceso de clasificación.

Espero que esto sea una explicación suficientemente clara. Siéntase libre de comentar si cree que se necesita más información.

¡Salud!

inestable
fuente
No es una respuesta adecuada porque solo realiza menos que y mayor que las verificaciones y no la verificación igual.
Steel Brain
tampoco aporta nada nuevo a la mesa, en comparación con ninguna de las respuestas que han estado allí desde ~ 2011.
Amenthes
1

Introdujo las mejores respuestas en un prototipo para ordenar por clave.

Array.prototype.alphaSortByKey= function (key) {
    this.sort(function (a, b) {
        if (a[key] < b[key])
            return -1;
        if (a[key] > b[key])
            return 1;
        return 0;
    });
    return this;
};
msponagle
fuente
0

Puedes usar algo similar para deshacerte de mayúsculas y minúsculas

users.sort(function(a, b){

  //compare two values
  if(a.firstname.toLowerCase() < b.firstname.toLowerCase()) return -1;
  if(a.firstname.toLowerCase() > b.firstname.toLowerCase()) return 1;
  return 0;

})
SAN_WEB
fuente
77
La misma respuesta que la de Mrchief. Con la desventaja adicional de que toLowerCase se realiza cuatro veces por comparación en lugar de dos veces.
Amenthes
0

Mi implementación funciona muy bien en versiones anteriores de ES:

sortObject = function(data) {
    var keys = Object.keys(data);
    var result = {};

    keys.sort();

    for(var i = 0; i < keys.length; i++) {
        var key = keys[i];

        result[key] = data[key];
    }

    return result;
};
extremo
fuente
0

Solo para el registro, si desea tener una función de clasificación con nombre, la sintaxis es la siguiente:

let sortFunction = (a, b) => {
 if(a.firstname < b.firstname) { return -1; }
 if(a.firstname > b.firstname) { return 1; }
 return 0;
})
users.sort(sortFunction)

Tenga en cuenta que lo siguiente NO funciona:

users.sort(sortFunction(a,b))
Katinka Hesselink
fuente