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

25
demandé sur Community 2014-06-09 02:27:22

7 réponses

_.sortByAll méthode dans lodash version 3:

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 }
// ];
15
répondu Tomas Kirda 2017-07-07 11:36:44

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.

31
répondu Daniel Kaplan 2015-08-20 16:26:37

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.

12
répondu kenjiru 2017-09-09 19:49:27

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.

10
répondu KimKha 2016-09-21 10:28:21

Avec ES6 syntaxe facile et lodash

sortBy(item.sortData, (item) => (-item.a), (item) => (-item.b))
5
répondu Cem Arguvanlı 2017-04-19 16:09:25

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)
});

Il fonctionne et vous pouvez le voir dans Plunker

0
répondu David Martin 2015-09-17 15:03:11

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];
});
0
répondu 2016-06-10 07:49:46