Estou procurando classificar uma matriz de cerca de 200-300 objetos, classificando em uma chave específica e uma determinada ordem (asc / desc). A ordem dos resultados deve ser consistente e estável.
Qual seria o melhor algoritmo a ser usado e você poderia fornecer um exemplo de sua implementação em javascript?
Obrigado!
javascript
algorithm
sorting
William Casarin
fonte
fonte
Respostas:
É possível obter uma classificação estável a partir de uma função de classificação não estável.
Antes de classificar você obtém a posição de todos os elementos. Em sua condição de classificação, se ambos os elementos forem iguais, você classifica pela posição.
Tada! Você tem um tipo estável.
Escrevi um artigo sobre isso no meu blog se você quiser saber mais sobre essa técnica e como implementá-la: http://blog.vjeux.com/2010/javascript/javascript-sorting-table.html
fonte
Como você está procurando por algo estável, a classificação por mesclagem deve servir.
http://www.stoimen.com/blog/2010/07/02/friday-algorithms-javascript-merge-sort/
O código pode ser encontrado no site acima:
EDITAR:
De acordo com esta postagem , parece que Array.Sort em algumas implementações usa uma classificação por mesclagem.
fonte
Array#shift
pode funcionar em tempo O (n) e, portanto, vocêmerge
em O (n * n).Versão um pouco mais curta da mesma coisa usando recursos do ES2017, como funções de seta e desestruturação:
Função
Ele aceita matriz de entrada e função de comparação:
Ele também retorna uma nova matriz em vez de fazer uma classificação local, como a função Array.sort () embutida.
Teste
Se pegarmos a seguinte
input
matriz, inicialmente classificada porweight
:Em seguida, classifique-o
height
usandostableSort
:Resulta em:
No entanto, classificar a mesma
input
matriz usando o integradoArray.sort()
(no Chrome / NodeJS):Retorna:
Recursos
Atualizar
fonte
stableSort
função é realmente uma ótima solução!Eu sei que esta pergunta foi respondida há algum tempo, mas acontece que tenho uma boa implementação estável de merge sort para Array e jQuery na minha área de transferência, então vou compartilhá-la na esperança de que alguns pesquisadores futuros possam achar útil.
Ele permite que você especifique sua própria função de comparação, assim como a
Array.sort
implementação normal .Implementação
Exemplo de uso
fonte
array.sort
, consulte o teste aqui para strings e inteiros -> jsfiddle.net/QC64jmergeSort
e nãosort
, portanto, não tem o objetivo de substituí-la. Às vezes, você só precisa de uma classificação de mesclagem estável, por exemplo, ao classificar tabelas por coluna.Você pode usar o seguinte polyfill para implementar uma classificação estável, independentemente da implementação nativa, com base na afirmação feita nesta resposta :
Executando os testes de desempenho implementados acima,
stableSort()
parece funcionar a cerca de 57% da velocidade dosort()
Chrome versão 59-61.O uso
.bind(compareFunction)
da função anônima encapsulada emstableSort()
aumentou o desempenho relativo de cerca de 38%, evitando uma referência de escopo desnecessária acompareFunction
em cada chamada, atribuindo-a ao contexto.Atualizar
Operador ternário alterado para curto-circuito lógico, que tende a ter um desempenho melhor em média (parece fazer uma diferença de 2-3% na eficiência).
fonte
O seguinte classifica a matriz fornecida, aplicando a função de comparação fornecida, retornando a comparação do índice original quando a função de comparação retorna 0:
O exemplo abaixo classifica uma matriz de nomes por sobrenome, mantendo a ordem dos sobrenomes iguais:
fonte
jQuery.expando.split( "" ).sort( ( a, b ) => 0 ).join( "" ) === jQuery.expando
Aqui está uma implementação estável. Ele funciona usando a classificação nativa, mas nos casos em que os elementos são comparados como iguais, você quebra os laços usando a posição do índice original.
um teste não completo
outra resposta aludiu a isso, mas não postou teh codez.
mas não é rápido de acordo com meu benchmark . Modifiquei um impl de classificação de mesclagem para aceitar uma função de comparação personalizada e foi muito mais rápido.
fonte
Você também pode usar Timsort. Este é um algoritmo muito complicado (mais de 400 linhas, portanto, nenhum código-fonte aqui), portanto, consulte a descrição da Wikipedia ou use uma das implementações JavaScript existentes:
Implementação GPL 3 . Empacotado como Array.prototype.timsort. Parece ser uma reescrita exata do código Java.
Implementação de domínio público Significada como um tutorial, o código de amostra mostra apenas seu uso com inteiros.
Timsort é um híbrido altamente otimizado de mergesort e shuffle sort e é o algoritmo de classificação padrão em Python e em Java (1.7+). É um algoritmo complicado, pois usa algoritmos diferentes para muitos casos especiais. Mas, como resultado, é extremamente rápido em uma ampla variedade de circunstâncias.
fonte
Um mergeSort simples de http://www.stoimen.com/blog/2010/07/02/friday-algorithms-javascript-merge-sort/
fonte
Tenho que classificar as matrizes multidimensionais por uma coluna arbitrária e depois por outra. Eu uso esta função para classificar:
Observe que ary.sort nunca retorna zero, que é onde algumas implementações da função "sort" tomam decisões que podem não estar certas.
Isso é muito rápido também.
fonte
Veja como você pode estender o objeto Array padrão JS com um método de protótipo utilizando MERGE SORT . Este método permite a classificação em uma chave específica (primeiro parâmetro) e uma determinada ordem ('asc' / 'desc' como segundo parâmetro)
Você pode testar isso colocando o snippet acima no console do seu navegador e, em seguida, tentando:
Ou faça o pedido com base em um campo específico em uma matriz de objetos:
fonte
Então eu precisava de uma classificação estável para meu aplicativo React + Redux, e a resposta de Vjeux aqui me ajudou. No entanto, minha solução (genérica) parece diferente das outras que vi aqui até agora, então estou compartilhando-a caso alguém tenha um caso de uso correspondente:
sort()
API, onde eu possa passar uma função de comparador.Minha solução é criar uma matriz digitada de e
indices
, em seguida, usar uma função de comparação para classificar esses índices com base na matriz a ser classificada. Em seguida, podemos usar o classificadoindices
para classificar o array original ou criar uma cópia classificada em uma única passagem. Se isso for confuso, pense desta forma: onde você normalmente passaria uma função de comparação como:Agora você usa:
A velocidade é boa; é basicamente o algoritmo de classificação embutido, mais duas passagens lineares no final e uma camada extra de sobrecarga de indireção do ponteiro.
Fico feliz em receber feedback sobre esta abordagem. Aqui está minha implementação completa disso:
fonte
Eu sei que isso foi bastante respondido. Eu só queria postar uma implementação rápida do TS para qualquer um que veio aqui procurando por isso.
O método não é mais executado no local, como a classificação nativa. Também quero ressaltar que não é o mais eficiente. Ele adiciona dois loops da ordem O (n). embora a própria classificação seja provavelmente O (n log (n)), portanto, é menor que isso.
Algumas das soluções mencionadas são mais eficientes, embora isso possa ser menos código, também usando interno
Array.prototype.sort
.(Para uma solução Javascript, basta remover todos os tipos)
fonte
De acordo com o v8 dev blog e caniuse.com
Array.sort
já é estável conforme exigido pelas especificações em navegadores modernos, então você não precisa lançar sua própria solução. A única exceção que vejo é o Edge, que em breve passará para o cromo e também o suportará.fonte
fonte
A classificação por contagem é mais rápida do que a classificação por mesclagem (ela é executada no tempo O (n)) e deve ser usada em inteiros.
Exemplo:
fonte
array [3, 1, 3]
hashes para[undefined, 1, undefined, 3]
. Obtemos dois valores não indefinidos, enquanto o algoritmo espera que haja três deles.