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:  "user@domain.com",
   firstname: "Anna",
   id: 318,
   lastAvatar: null,
   lastMessage: null,
   lastname: "Nickson",
   nickname: "anny"
};

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.


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!


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)
});

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);
})

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);

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


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()})

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.


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: "user@domain.com",
firstname: 'Anna',
id: 318,
"last_avatar": "<null>",
"last_message": "<null>",
lastname: 'Nickson',
nickname: 'anny'
},
{
bio: "<null>",
email: "user@domain.com",
firstname: 'Senad',
id: 318,
"last_avatar": "<null>",
"last_message": "<null>",
lastname: 'Nickson',
nickname: 'anny'
},
{
bio: "<null>",
email: "user@domain.com",
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;
});

¿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

Una notación más compacta:

user.sort(function(a, b){
    return a.firstname === b.firstname ? 0 : a.firstname < b.firstname ? -1 : 1;
})

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));
        })

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

4

tratar

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


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);}

2

en palabras simples, puedes usar este método

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

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!


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;
};

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;

})

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;
};

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))
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.