Classificar matriz por nome (alfabeticamente) em Javascript


646

Eu tenho uma matriz (veja abaixo para um objeto na matriz) que eu preciso classificar por nome usando JavaScript. Como eu posso fazer isso?

var user = {
   bio: null,
   email:  "user@domain.com",
   firstname: "Anna",
   id: 318,
   lastAvatar: null,
   lastMessage: null,
   lastname: "Nickson",
   nickname: "anny"
};

Respostas:


1067

Suponha que você tenha uma matriz users. Você pode usar users.sorte passar uma função que recebe dois argumentos e os compara (comparador)

Deve retornar

  • algo negativo se o primeiro argumento for menor que o segundo (deve ser colocado antes do segundo na matriz resultante)
  • algo positivo se o primeiro argumento for maior (deve ser colocado após o segundo)
  • 0 se esses dois elementos forem iguais.

No nosso caso, se dois elementos existirem ae bqueremos comparar a.firstnameeb.firstname

Exemplo:

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

Este código funcionará com qualquer tipo.

Observe que, na "vida real" ™, você frequentemente deseja ignorar maiúsculas e minúsculas, classificar corretamente sinais diacríticos, símbolos estranhos como ß etc. quando comparar seqüências de caracteres, portanto, pode usar localeCompare. Veja outras respostas para maior clareza.


5
Friggin awesome ... Estou classificando um nodelist por id ... funciona como um encanto. Thx a tonelada!
Cody

74
Para quem chega mais tarde, a resposta de Mrchief é melhor porque não faz distinção entre maiúsculas e minúsculas.
Mlienau #

25
@mlienau, eu não diria que é melhor ou pior. É apenas mais uma coisa
RiaD

19
@RiaD justo o suficiente. Apenas não consigo pensar em muitos casos de classificação alfabética de itens, incluindo maiúsculas e minúsculas, onde 'Zebra' aparece na lista antes de 'maçã' seria muito útil.
mlienau

15
Este código funcionará apenas em países de língua inglesa. Em outros países, você deve usar a resposta da ovunccetinalocaleCompare .
Spoike

545

O menor código possível com o ES6!

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

O suporte básico String.prototype.localeCompare () é universal!


27
De longe a melhor resposta se você está vivendo em 2017
nathanbirrell

52
Melhor resposta também se você mora em 2018;)
Simone

49
Provavelmente também será a melhor resposta para 2019.
Ahmad Maleki

23
2020 talvez? ou naaa?
precisa saber é o seguinte

15
ah cara, em 2030 a terra inunda e isso só funciona nas montanhas.
Starfs

343

Algo assim:

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
Ao classificar as strings 'toLowerCase ()' é muito importante - as letras maiúsculas podem afetar sua classificação.
MarzSocks

3
Caso alguém mais esteja se perguntando o que o toLowerCase afeta, não é muito:'a'>'A' //true 'z'>'a' //true 'A'>'z' //false
SimplGy

14
@SimplGy Eu diria que seu impacto é um pouco mais do que você está dando crédito. Por exemplo, conforme declarado nos comentários da resposta aceita, é importante saber se sua função de classificação classificará ou não a string 'Zebra'mais alta que a string 'apple', o que será feito se você não usar o .toLowerCase().
PrinceTyke

1
@PrinceTyke, sim, esse é um bom caso. 'Z' < 'a' // truee'z' < 'a' // false
SimplGy 5/08/2015

2
Todos os pontos válidos e eu diria que a classificação é sempre um tipo de coisa "depende". Se você estiver classificando por nomes, a distinção entre maiúsculas e minúsculas pode não importar. Em outros casos, pode ser. Independentemente disso, acho que adotar a situação específica não é difícil depois que você obtém a ideia central.
Mrchief 5/08/2015

336

Se as cadeias comparadas contiverem caracteres unicode, você poderá usar a localeComparefunção de Stringclasse da seguinte maneira:

users.sort(function(a,b){
    return a.firstname.localeCompare(b.firstname);
})

3
String.localeCompare não é compatível com o Safari e IE <11 :)
CORSAIR

13
@ CORSAIR é suportado, é apenas o segundo e o terceiro parâmetro que não são suportados.
Codler

6
@CORSAIR, o uso no exemplo é suportado em todos os principais navegadores IE: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . O LocaleCompare também leva em consideração a capitalização, por isso acho que essa implementação deve ser considerada a melhor prática.
Matt Jensen

9
users.sort ((a, b) => a.firstname.localeCompare (b.firstname)) // Versão curta e doce do ES6!
precisa saber é o seguinte

4
tanques mano. no uso do ES6users.sort((a, b) => a.name.localeCompare(b.name))
Mohmmad Ebrahimi Aval 11/10

32

Nice little ES6 one liner:

users.sort((a, b) => a.firstname !== b.firstname ? a.firstname < b.firstname ? -1 : 1 : 0);

2
Este está incompleto, pois não lida com valores iguais corretamente.
Karl-Johan Sjögren

1
Claro, obrigado por manchas que, eu adicionei um cheque de valores correspondentes
Sam Logan

não é mau Eu acho que se você realmente quer tudo em uma linha, ternários aninhados ficar confusa para facilitar a leitura embora
russter

24

Podemos usar o localeCompare, mas também precisamos verificar as chaves quanto aos valores de falsey

O código abaixo não funcionará se uma entrada estiver com lname ausente.

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

Então, precisamos verificar o valor de Falsey como abaixo

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

OU

podemos usar lodash, é muito simples. Ele detectará os valores retornados, ou seja, número ou sequência e fará a classificação de acordo.

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

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


2
Lodash é bem arrumado! Não tinha ouvido falar disso antes. Funciona bem!
Derk Jan Speelman

15

O underscorejs oferece a muito boa função _.sortBy:

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

ou você pode usar uma função de classificação personalizada:

_.sortBy([{a:"b"},{a:"c"},{a:"a"}], function(i) {return i.a.toLowerCase()})

2
o segundo exemplo envolve retornar strings. Será que sortBydetectar os valores devolvidos são cadeias e, portanto, realiza uma classificação alfabética? Obrigado
superjos

12

Em caso estamos classificando nomes ou algo com caracteres especiais, como ñ ou AEIOU (commons em espanhol) nós poderíamos usar o params locales ( es para o espanhol, neste caso) e opções como este:

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)

As opções oficiais de localidade podem ser encontradas aqui em iana , es (espanhol), de (alemão), fr (francês). Sobre a sensibilidade base significa:

Somente cadeias que diferem em letras base são comparadas como desiguais. Exemplos: a ≠ b, a = á, a = A.


8

Basicamente, você pode classificar matrizes com o método sort, mas se você quiser classificar objetos, precisará passar a função para classificar o método do array, portanto, darei um exemplo usando seu array

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 que retornar 0 no final?
Nobita

=, Quando as cordas são mesmo
Senad Meskin

mas nesse caso não deve elseser removido? Caso contrário, isso return 0nunca será lido
Nobita

2
que não é "coisa", é "else if"
Senad Meskin


8

Uma notação mais compacta:

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

é mais compacto, mas viola seu contrato: sign(f(a, b)) =-sign(f(b, a))(para a = b)
Riad

3
return a.firstname == b.firstnamedeve usar ===para completude
puiu

6

também para classificação asec e desc, você pode usar isso: suponha que tenhamos uma variável SortType que especifica a classificação crescente ou a classificação descendente desejada:

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

5

Uma função generalizada pode ser escrita como abaixo

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

você pode passar os parâmetros abaixo

  1. Os dados que você deseja classificar
  2. A propriedade nos dados deve ser classificada
  3. O último parâmetro é do tipo booleano. Ele verifica se você deseja classificar por ascendente ou descendente

4

tentar

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


2
a função de classificação deve retornar -1,0,1. este retorna apenas -1,1.
Radu Luncasu

@RaduLuncasu - você pode fornecer dados de teste (matriz de usuários) que mostram que a solução acima dá resultado errado? (até onde eu sei, a falta de zero não é problema) #
Kamil Kiełczewski 26/06/19

Se compareFunction (a, b) retornar 0, deixe aeb inalterados um com o outro, mas classificados com relação a todos os elementos diferentes.
Radu Luncasu


@RaduLuncasu ok, mas essas informações não significam que zero é obrigatório. A melhor maneira de mostrar que é preparar os dados que não funciona - mas tanto eu sei que isso é impossível - por exemplo[9,8,7,6,5,1,2,3].sort((a,b) => a<b ? -1 : 1)
Kamil Kiełczewski

3

Você pode usar isso 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

em palavras simples, você pode usar esse método

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

1

Você pode usar o método de matriz incorporado - sort. Esse método usa um método de retorno de chamada como um 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"]


Pontos principais a serem observados para a compreensão deste código.

  1. O método personalizado, nesse caso, myCustomSortdeve retornar +1 ou -1 para cada comparação de pares de elementos (da matriz de entrada).
  2. Use toLowerCase()/ toUpperCase()no método de retorno de chamada de classificação personalizado, para que a diferença entre maiúsculas e minúsculas não afete a correção do processo de classificação.

Espero que esta seja uma explicação suficientemente clara. Sinta-se livre para comentar se você acha que são necessárias mais informações.

Felicidades!


Não é uma resposta adequada porque executa apenas menos e maior que verificações e não a verificação igual.
Steel Brain

também não traz nada de novo para a mesa, em comparação com qualquer uma das respostas que estão lá desde ~ 2011.
Amenthes

1

Introduziu as principais respostas em um protótipo para classificar por chave.

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

Você pode usar algo semelhante, para se livrar da distinção entre maiúsculas e 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;

})

7
Mesma resposta que a de Mrchief. Com a desvantagem adicional de que o toLowerCase é feito quatro vezes por comparação, em vez de duas vezes.
Amenthes

0

Minha implementação, funciona muito bem em versões mais antigas do 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

Apenas para o registro, se você deseja ter uma função de classificação nomeada, a sintaxe é a seguinte:

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

Observe que o seguinte NÃO funciona:

users.sort(sortFunction(a,b))
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.