Ordenação de números no JavaScript não funciona?

(Last Updated On: 10 de maio de 2017)

Digamos que você tem um array de números em JavaScript:

var lista = [10,1, 5, 9, 8, 12, 15];

E queremos ordená-lo. O que fazer? Usar a função sort() claro!

lista.sort();
// [1, 10, 12, 15, 5, 8, 9]

Repare no resultado: não está na ordem esperada. Essa questão foi trazida ao fórum da Alura pelo Jean Cesar Batista.

A grande questão é que a função sort() usa por padrão a ordenação alfabética baseada na tabela Unicode. Apesar de inesperado isso está documentado. A solução é usar a nossa própria função de comparação.

Implementando função de comparação

O sort recebe opcionalmente uma função de comparação que, dados dois valores, deve devolver um número inteiro:

  • Se for 0 indica que são iguais
  • Se for -1 indica que o primeiro valor é menor
  • Se for 1, o segundo é menor.

Podemos criar essa função:

function comparaNumeros(a,b) {
  if (a == b)  return 0;
    if (a < b) return -1;
    if (a > b) return 1;
}

E chamamos o sort passando a função:

lista.sort(comparaNumeros);
// [1, 5, 8, 9, 10, 12, 15]

Funciona!

Simplicando a implementação

E, claro, podemos simplificar bastante esse código.

É possível trocar a função nomeada pra ser anônima. E trocar os três IFs por uma conta simples: a - b.

Repare que o resultado dessa conta é sempre 0 se forem iguais, -1 se a é menor e 1 se b é menor. Exatamente o que precisamos.

Juntanto tudo isso com a sintaxe de arrow functions do ES6 pra escrever menos, podemos simplesmente fazer:

lista.sort((a, b) => a - b);
// [1, 5, 8, 9, 10, 12, 15]

O que achou? Bem enxuto, concorda? Aproveite e deixe o seu comentário sobre o que achou da ordenação de array no JavaScript.

E que tal receber conteúdos como este no seu e-mail? Gostou da ideia? É simples, basta apenas assinar a nossa newsletter!

Fique por dentro

  • Fellipe Souto

    Uma pequena dúvida, no trecho:

    “Repare que o resultado dessa conta é sempre 0 se forem iguais, -1 se a é menor e 1 se b é menor…”

    não seria mais correto dizer que, o resultado de (a – b) é sempre:

    0 se forem iguais,
    < 0 se a for menor que b,

    0 se a for maior que b

    No texto ficou um pouco confuso, porque nem sempre o resultado da subtração será 1 ou -1.

    Fora isso muito bom o artigo, meus parabéns.

  • Claudenir Freitas

    var lista = [10,1, 5, 9, 8, 12, 15, -29, 90];
    lista.sort((a, b) => a – b); === lista.sort((a, b) => a > b);

    A saída é a mesma, algum motivo de qual melhor forma implementar? Fiz alguns testes e ambos tem o mesmo comportamento.

    • Wanderson Macêdo

      Oi @claudenirfreitas:disqus tudo bem? A primeira, com a subtração é a forma correta. Apesar desse exemplo que você deu funcionar bem as duas formas, caso o array tenha números repetidos a segunda implementação fica confusa.

      Isso por que ela não prevê que um resultado pode ser 0. A diferença também é que a primeira forma, devolve um número que define um posicionamento, a segunda um boleano, certo que por baixo dos panos o -1 e 1 serão false e true, mas o 0, também seria false e no tratamento do posicionamento, daria problema.

      Deu pra entender?

      • Claudenir Freitas

        Opa @wandersonmaceds:disqus , tranquilo e contigo?
        Consegui captar a ideia sim, dá uma olhada neste novo teste:
        const lista = [10,1, 5, 9, 8, 3,5,6,7,2,4,6,7,32,12, 15, -29, 90, 90]; // 19 itens
        lista.sort((a, b) => a > b) !== lista.sort((a, b) => a – b)
        No primeiro caso ele não conseguiu ordenar de acordo, logo fazendo uso da subtração é a melhor prática mesmo e é o que a documentação sugere…
        Agradecido @Wanderson Macêdo e a Alura!

        • Bruno Paschoali

          Uma coisa bacana do seu comentário é “e é o que a documentação sugere”. Com exceção de algum caso raro específico, seguir exatamente o que diz na documentação é sempre o mais ideal 🙂

          • Claudenir Freitas

            Exato Bruno!

      • Pedro Ávila

        Wanderson, -1 é truthy, considerando números, somente 0 e NaN são falsy. Isto considerando que typeof(NaN) === “number” // true

        • Wanderson Macêdo

          Oi @disqus_bfUXQWFEdG:disqus , obrigado pela observação, você está certo. Eu me enganei no comentário acima. -1 e 1 seriam true e 0 false, bagunçando a ordenação. Lembrando que não são os valores boleanos necessariamente que ordenam a listagem, mas sim os numéricos.

  • Juscilan Moreto

    Se for decrescrente : lista.sort((a, b) => b – a);

Próximo ArtigoInovação e criatividade: veja como o design thinking pode ajudá-lo