Estou tentando classificar uma matriz com objetos com base em vários atributos. Ou seja, se o primeiro atributo é o mesmo entre dois objetos, um segundo atributo deve ser usado para comapar os dois objetos. Por exemplo, considere a seguinte matriz:
var patients = [
[{name: 'John', roomNumber: 1, bedNumber: 1}],
[{name: 'Lisa', roomNumber: 1, bedNumber: 2}],
[{name: 'Chris', roomNumber: 2, bedNumber: 1}],
[{name: 'Omar', roomNumber: 3, bedNumber: 1}]
];
Classificando-os pelo roomNumber
atributo, eu usaria o seguinte código:
var sortedArray = _.sortBy(patients, function(patient) {
return patient[0].roomNumber;
});
Isso funciona bem, mas como faço para que 'John' e 'Lisa' sejam classificados corretamente?
fonte
[0]
indexador é necessário porque no exemplo original,patients
é uma matriz de matrizes. É também por isso que a "solução mais simples" na postagem do blog mencionada em outro comentário não funcionará aqui.Aqui está um truque hacky que às vezes uso nesses casos: combine as propriedades de forma que o resultado seja classificável:
No entanto, como eu disse, isso é muito hacky. Para fazer isso corretamente, você provavelmente gostaria de usar o
sort
método principal do JavaScript :Claro, isso classificará seu array no lugar. Se você quiser uma cópia classificada (como
_.sortBy
daria a você), clone a matriz primeiro:Por causa do tédio, acabei de escrever uma solução geral (para classificar por qualquer número arbitrário de chaves) para isso também: dê uma olhada .
fonte
return [patient[0].roomNumber, patient[0].name];
sem ojoin
?compare
os valores do identificador que não são valores primitivos -undefined
,null
ou objetos simples?Sei que estou atrasado para a festa, mas queria acrescentar isso para quem precisa de uma solução mais limpa e rápida que as já sugeridas. Você pode encadear chamadas sortBy na ordem da propriedade menos importante para a propriedade mais importante. No código a seguir, crio uma nova matriz de pacientes classificados por Nome em RoomNumber a partir da matriz original chamada pacientes .
fonte
btw seu inicializador para pacientes é um pouco estranho, não é? por que você não inicializa esta variável como isto -como um verdadeiro array de objetos -você pode fazer isso usando _.flatten () e não como um array de arrays de um único objeto, talvez seja um problema de digitação):
Classifiquei a lista de maneira diferente e coloquei Kiko na cama de Lisa; apenas para se divertir e ver que mudanças seriam feitas ...
inspecione classificado e você verá isso
então minha resposta é: use uma matriz em sua função de retorno de chamada, isso é bastante semelhante à resposta de Dan Tao , apenas esqueci a junção (talvez porque eu removi a matriz de matrizes de item único :))
Usando sua estrutura de dados, então seria :
e um teste seria interessante ...
fonte
Nenhuma dessas respostas é ideal como método de propósito geral para o uso de vários campos em uma classificação. Todas as abordagens acima são ineficientes, pois exigem a classificação da matriz várias vezes (o que, em uma lista grande o suficiente, pode tornar as coisas muito lentas) ou geram grandes quantidades de objetos de lixo que a VM precisará limpar (e, por fim, desacelerar o programa desativado).
Esta é uma solução que é rápida, eficiente, permite fácil classificação reversa e pode ser usada com
underscore
oulodash
, ou diretamente comArray.sort
A parte mais importante é o
compositeComparator
método, que pega uma matriz de funções de comparador e retorna uma nova função de comparador composto.Você também precisará de uma função de comparador para comparar os campos que deseja classificar. A
naturalSort
função criará um comparador para um determinado campo. Escrever um comparador para classificação reversa também é trivial.(Todo o código até agora é reutilizável e pode ser mantido no módulo utilitário, por exemplo)
Em seguida, você precisa criar o comparador composto. Para nosso exemplo, seria assim:
Isso classificará pelo número do quarto, seguido pelo nome. Adicionar critérios de classificação adicionais é trivial e não afeta o desempenho da classificação.
Retorna o seguinte
A razão pela qual eu prefiro este método é que ele permite uma classificação rápida em um número arbitrário de campos, não gera muito lixo ou executa concatenação de strings dentro da classificação e pode ser facilmente usado para que algumas colunas sejam classificadas de forma reversa enquanto as colunas de ordem usam natural ordenar.
fonte
Exemplo simples de http://janetriley.net/2014/12/sort-on-multiple-keys-with-underscores-sortby.html (cortesia de @MikeDevenney)
Código
Com Seus Dados
fonte
Talvez os motores de underscore.js ou apenas Javascript sejam diferentes agora de quando essas respostas foram escritas, mas consegui resolver isso apenas retornando um array das chaves de classificação.
Em ação, consulte este violino: https://jsfiddle.net/mikeular/xenu3u91/
fonte
Basta retornar uma matriz de propriedades com as quais deseja classificar:
Sintaxe ES6
Sintaxe ES5
Isso não tem efeitos colaterais na conversão de um número em string.
fonte
Você pode concatenar as propriedades que deseja classificar no iterador:
ou algo equivalente.
NOTA: Uma vez que você está convertendo o atributo numérico roomNumber em uma string, você teria que fazer algo se tivesse números de quartos> 10. Caso contrário, 11 virá antes de 2. Você pode preencher com zeros à esquerda para resolver o problema, ou seja, 01 em vez de 1
fonte
Acho melhor você usar em
_.orderBy
vez desortBy
:fonte
_.orderBy
funciona, mas é um método da biblioteca lodash, não sublinhado: lodash.com/docs/4.17.4#orderBy Lodash é principalmente um substituto imediato para o sublinhado, portanto, pode ser apropriado para o OP.Se você estiver usando Angular, poderá usar seu filtro de número no arquivo html em vez de adicionar qualquer manipulador JS ou CSS. Por exemplo:
Nesse exemplo, se val = 1234567, será exibido como
Exemplo e mais orientações em: https://docs.angularjs.org/api/ng/filter/number
fonte