Comment puis-je utiliser lodash/underscore pour trier par plusieurs champs imbriqués?
je veux faire quelque chose comme ceci:
var data = [
{
sortData: {a: 'a', b: 2}
},
{
sortData: {a: 'a', b: 1}
},
{
sortData: {a: 'b', b: 5}
},
{
sortData: {a: 'a', b: 3}
}
];
data = _.sortBy(data, ["sortData.a", "sortData.b"]);
_.map(data, function(element) {console.log(element.sortData.a + " " + element.sortData.b);});
Et l'ont sortie:
"a 1"
"a 2"
"a 3"
"b 5"
Malheureusement, cela ne fonctionne pas et le tableau reste triés dans sa forme originale. cela fonctionnerait si les champs n'étaient pas imbriqués dans le sortData
. Comment puis-je utiliser lodash/underscore pour trier un tableau d'objets par Plus d'un champ imbriqué?
j'ai transformé ceci en une requête de fonctionnalité de lodash: https://github.com/lodash/lodash/issues/581
7 réponses
https://github.com/lodash/lodash/blob/3.10.1/doc/README.md#_sortbyallcollection-iteratees
Lodash la version 4, il a été unifié:
https://lodash.com/docs#sortBy
Autre option serait de trier les valeurs vous-même:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
function compareValues(v1, v2) {
return (v1 > v2)
? 1
: (v1 < v2 ? -1 : 0);
};
var data = [
{ a: 2, b: 1 },
{ a: 2, b: 2 },
{ a: 1, b: 3 }
];
data.sort(function (x, y) {
var result = compareValues(x.a, y.a);
return result === 0
? compareValues(x.b, y.b)
: result;
});
// data after sort:
// [
// { a: 1, b: 3 },
// { a: 2, b: 1 },
// { a: 2, b: 2 }
// ];
mise à Jour: Voir les commentaires ci-dessous, ce n'est pas une bonne solution dans la plupart des cas.
Quelqu'un a gentiment répondu dans le numéro que j'ai créé. Voici sa réponse, inline:
_.sortBy(data, function(item) {
return [item.sortData.a, item.sortData.b];
});
Je n'ai pas réalisé que vous êtes autorisé à retour un tableau de cette fonction. La documentation n'en parle pas.
Si vous avez besoin de spécifier le sens de tri, vous pouvez utiliser _.orderBy
avec le tableau de fonctions syntaxe de Lodash 4.x:
_.orderBy(data, [
function (item) { return item.sortData.a; },
function (item) { return item.sortData.b; }
], ["asc", "desc"]);
cela va trier la première ascension par propriété a
, et pour les objets qui ont la même valeur pour la propriété a
, va les trier Descendant Par propriété b
.
cela fonctionne comme prévu lorsque le a
et b
les propriétés ont différents types.
Voici un jsbin exemple à l'aide de cette syntaxe.
La formidable moyen simple est:
_.sortBy(data, [function(item) {
return item.sortData.a;
}, function(item) {
return item.sortData.b;
}]);
Je l'ai trouvé à partir de vérifier le code source de lodash, il vérifie toujours la fonction un par un.
j'Espère que vous aider.
Avec ES6 syntaxe facile et lodash
sortBy(item.sortData, (item) => (-item.a), (item) => (-item.b))
je pense que cela pourrait fonctionner dans la plupart des cas avec un trait de soulignement:
var properties = ["sortData.a", "sortData.b"];
data = _.sortBy(data, function (d) {
var predicate = '';
for (var i = 0; i < properties.length; i++)
{
predicate += (i == properties.length - 1
? 'd.' + properties[i]
: 'd.' + properties[i] + ' + ')
}
return eval(predicate)
});
si le problème est qu'un entier est converti en chaîne, ajoutez des zéros avant l'entier pour qu'il ait la même longueur que le plus long de la collection:
var maxLength = _.reduce(data, function(result, item) {
var bString = _.toString(item.sortData.b);
return result > bString.length ? result : bString.length;
}, 0);
_.sortBy(data, function(item) {
var bString = _.toString(item.sortData.b);
if(maxLength > bString.length) {
bString = [new Array(maxLength - bString.length + 1).join('0'), bString].join('');
}
return [item.sortData.a, bString];
});