Eu tenho uma matriz de objetos JavaScript:
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
Como posso classificá-los pelo valor de last_nom
JavaScript?
Eu sei sort(a,b)
, mas isso parece funcionar apenas em strings e números. Preciso adicionar um toString()
método aos meus objetos?
javascript
arrays
sorting
Tyrone Slothrop
fonte
fonte
Respostas:
É fácil escrever sua própria função de comparação:
Ou em linha (com Marco Demaio):
fonte
return a.last_nom.localeCompare(b.last_nom)
vai funcionar também.return a.value - b.value;
(ASC)localeCompare
é importante ao usar caracteres acentuados em idiomas estrangeiros e também mais elegante.Você também pode criar uma função de classificação dinâmica que classifica objetos pelo valor que você passa:
Então você pode ter uma matriz de objetos como este:
... e funcionará quando você fizer:
Na verdade, isso já responde à pergunta. A parte abaixo está escrita porque muitas pessoas entraram em contato comigo, reclamando que não funciona com vários parâmetros .
Parâmetros múltiplos
Você pode usar a função abaixo para gerar funções de classificação com vários parâmetros de classificação.
O que permitiria que você fizesse algo assim:
Matriz de subclassificação
Para os sortudos entre nós que podem usar o ES6, o que permite estender os objetos nativos:
Isso permitiria isso:
fonte
dynamicSort()
exemplo acima colocará letras maiúsculas à frente de letras minúsculas. Por exemplo, se eu tenho os valoresAPd
,Aklin
, eAbe
- os resultados em uma ASC tipo deve serAbe
,Aklin
,APd
. Mas, com o seu exemplo, os resultados sãoAPd
,Abe
,Aklin
. Enfim, para corrigir esse comportamento?var result = a[property].localeCompare(b[property]);
vez devar result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
.if( !isNaN(a[property]) ) a[property] = Number(a[property]); if( !isNaN(b[property]) ) b[property] = Number(b[property]);
No ES6 / ES2015 ou posterior, você pode fazer o seguinte:
Antes do ES6 / ES2015
fonte
last_nom
usar apenas o número na matriz1
:?objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom, undefined, {numberic: true}));
underscore.js
use sublinhado, é pequeno e incrível ...
fonte
var sortedObjs = _.sortBy( objs, 'first_nom' );
.objs
vai não ser ordenados-se como um resultado disso. A função retornará uma matriz classificada. Isso tornaria mais explícito.var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse();
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"> </script>
Lodash
para aqueles que preferem essevar sortedObjs = _.sortBy( objs, 'first_nom' );
ou se você quiser em uma ordem diferente:var sortedObjs = _.orderBy( objs, ['first_nom'],['dsc'] );
Não entenda por que as pessoas tornam isso tão complicado:
Para motores mais rigorosos:
Troque o operador para ordená-lo por ordem alfabética inversa.
fonte
if(a.count == b.count) return a.name > b.name; else return a.count > b.count;
Se você tiver sobrenomes duplicados, poderá classificá-los por nome.
fonte
b
deve vir depoisa
na matriz. Se um número positivo for retornado, isso significa quea
deve vir depoisb
. Se0
for retornado, significa que eles são considerados iguais. Você sempre pode ler a documentação: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…1, 0, -1
antes de perguntar aqui. Só não estava encontrando as informações necessárias.Solução simples e rápida para esse problema usando herança de protótipo:
Exemplo / Uso
Atualização: não modifica mais a matriz original.
fonte
A partir de 2018, existe uma solução muito mais curta e elegante. Apenas use. Array.prototype.sort () .
Exemplo:
fonte
a.value - b.value
usado para comparar os atributos do objeto ( neste caso, números ) pode ser adotado para os vários tempos de dados. Por exemplo, regex pode ser usado para comparar cada par de cadeias vizinhas .Resposta antiga que não está correta:
ATUALIZAR
Do comentário de Beauchamp:
Formato mais legível:
Sem ternários aninhados:
Explicação:
Number()
será convertidotrue
para1
efalse
para0
.fonte
arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))
Em vez de usar uma função de comparação personalizada, você também pode criar um tipo de objeto com o
toString()
método personalizado (que é invocado pela função de comparação padrão):fonte
Lodash.js (superconjunto de Underscore.js )
É bom não adicionar uma estrutura para cada peça simples de lógica, mas confiar em estruturas de utilidade bem testadas pode acelerar o desenvolvimento e reduzir a quantidade de bugs.
Lodash produz código muito limpo e promove uma programação mais funcional estilo de . Em um vislumbre, fica claro qual é a intenção do código.
A questão do OP pode simplesmente ser resolvida como:
Mais informações? Por exemplo, temos o seguinte objeto aninhado:
Agora podemos usar a abreviação _.property
user.age
para especificar o caminho para a propriedade que deve ser correspondida. Classificaremos os objetos do usuário pela propriedade age aninhada. Sim, permite a correspondência de propriedades aninhadas!Deseja que seja revertido? Sem problemas. Use _.reverse .
Deseja combinar ambos usando corrente ?
Ou quando você prefere o fluxo sobre a corrente
fonte
Você pode usar
Caminho mais fácil: Lodash
( https://lodash.com/docs/4.17.10#orderBy )
Esse método é como _.sortBy, exceto que permite especificar as ordens de classificação dos iterados para classificar. Se pedidos não for especificado, todos os valores serão classificados em ordem crescente. Caso contrário, especifique uma ordem de "desc" para decrescente ou "asc" para ordem de classificação crescente dos valores correspondentes.
Argumentos
coleção (matriz | objeto): a coleção para iterar. [iteratees = [_. identidade]] (Matriz [] | Função [] | Objeto [] | string []): Os iterativos para classificar. [orders] (string []): as ordens de classificação dos iterados.
Devoluções
(Matriz): retorna a nova matriz classificada.
fonte
Há muitas boas respostas aqui, mas gostaria de salientar que elas podem ser estendidas de maneira muito simples para obter uma classificação muito mais complexa. A única coisa que você precisa fazer é usar o operador OR para encadear funções de comparação como esta:
onde
fn1
,fn2
... são as funções de classificação que retorno [-1,0,1]. Isso resulta em "classificação por fn1", "classificação por fn2", que é praticamente igual a ORDER BY no SQL.Essa solução é baseada no comportamento do
||
operador que avalia a primeira expressão avaliada que pode ser convertida em true .A forma mais simples possui apenas uma função embutida como esta:
Tendo duas etapas em
last_nom
, afirst_nom
ordem de classificação ficaria assim:Uma função de comparação genérica pode ser algo como isto:
Esta função pode ser estendida para suportar campos numéricos, distinção entre maiúsculas e minúsculas, tipos de dados arbitrários etc.
Você pode usá-lo com encadeamento por prioridade de classificação:
O ponto aqui é que o JavaScript puro com abordagem funcional pode levar um longo caminho sem bibliotecas externas ou código complexo. Também é muito eficaz, já que nenhuma análise de string precisa ser feita
fonte
Exemplo de uso:
Roteiro:
fonte
1, 0, -1
são usados para a classificação. Mesmo com a sua explicação acima, que parece muito boa - ainda não estou entendendo direito. Eu sempre penso-1
como ao usar a propriedade length da matriz, ou seja:arr.length = -1
significa que o item não foi encontrado. Provavelmente estou misturando as coisas aqui, mas você poderia me ajudar a entender por que os dígitos1, 0, -1
são usados para determinar a ordem? Obrigado.a
eb
, sea
for maior queb
adicionar 1 ao índice dea
e colocá-lo para trásb
, sea
for menor queb
, subtraia 1 dea
e coloque-o na frente deb
. Sea
eb
são iguais, adicione 0 aa
e deixe-o onde está.Eu não vi essa abordagem específica sugerida, então aqui está um método de comparação conciso que eu gosto de usar que funciona para ambos
string
enumber
:Aqui está uma explicação de
sortBy()
:sortBy()
aceita umfn
que seleciona qual valor de um objeto usar como comparação e retorna uma função que pode ser passada diretamente paraArray.prototype.sort()
. Neste exemplo, estamos usandoo.last_nom
como valor para comparação, portanto, sempre que recebermos dois objetosArray.prototype.sort()
, comoe
nós usamos
para compará-los.
Lembrando que
fn = o => o.last_nom
, podemos expandir a função de comparação para o equivalenteO
||
operador OR lógico tem uma funcionalidade de curto-circuito que é muito útil aqui. Por causa de como funciona, o corpo da função acima significaComo um bônus adicional, aqui está o equivalente no ECMAScript 5 sem funções de seta, que infelizmente é mais detalhado:
fonte
Sei que essa pergunta é muito antiga, mas não vi nenhuma implementação semelhante à minha.
Esta versão é baseada no idioma de transformação Schwartzian .
Aqui está um exemplo de como usá-lo:
fonte
Classificação (mais) Matrizes complexas de objetos
Como você provavelmente encontra estruturas de dados mais complexas como essa matriz, eu expandiria a solução.
TL; DR
Problema
Encontrei o abaixo e não consegui alterá-lo. Também não queria achatar o objeto temporariamente. Também não queria usar sublinhado / lodash, principalmente por razões de desempenho e diversão para implementá-lo.
Objetivo
O objetivo é classificá-lo principalmente por
People.Name.name
e secundariamente porPeople.Name.surname
Obstáculos
Agora, na solução base, usa a notação de colchete para calcular as propriedades para classificar dinamicamente. Aqui, porém, teríamos que construir a notação de colchete dinamicamente também, já que você esperaria algo como
People['Name.name']
funcionassem - o que não.Simplesmente fazer
People['Name']['name']
, por outro lado, é estático e só permite que você desça n nível ésimo.Solução
A principal adição aqui será descer a árvore de objetos e determinar o valor da última folha, você deve especificar, bem como qualquer folha intermediária.
Exemplo
Exemplo de trabalho no JSBin
fonte
Mais uma opção:
classifica em ascensão por padrão.
fonte
Uma função simples que classifica uma matriz de objeto por uma propriedade
Uso:
fonte
Uma maneira simples:
Veja que
'.toLowerCase()'
é necessário para evitar erros na comparação de cadeias.fonte
objs.sort( (a,b) => b.last_nom.toLowerCase() < a.last_nom.toLowerCase() );
parâmetros de desc adicionais para o código Ege Özcan
fonte
Combinando a solução dinâmica do Ege com a ideia de Vinay, você obtém uma solução robusta e agradável:
Uso:
fonte
Seguindo o seu exemplo, você precisa classificar por dois campos (sobrenome, nome) e não por um. Você pode usar a biblioteca Alasql para fazer esse tipo em uma linha:
Experimente este exemplo em jsFiddle .
fonte
fonte
Dado o exemplo original:
Classifique por vários campos:
Notas
a.localeCompare(b)
é universalmente suportado e retorna -1,0,1 sea<b
,a==b
,a>b
respectivamente.||
na última linha dálast_nom
prioridade sobrefirst_nom
.var age_order = left.age - right.age;
return -last_nom_order || -first_nom_order || -age_order;
fonte
Tente isso,
fonte
Pode ser necessário convertê-los para letras minúsculas para evitar confusões.
fonte
fonte
Usando Ramda,
npm install ramda
fonte
Este é um problema simples, não sei por que as pessoas têm uma solução tão complexa.
Uma função de classificação simples (baseada no algoritmo de classificação rápida):
Use exemplo:
fonte