en utilisant lodash .groupBy. comment ajouter vos propres clés pour une sortie groupée?


104

J'ai ces exemples de données renvoyés par une API.

J'utilise Lodash _.groupBypour convertir les données en un objet que je peux mieux utiliser. Les données brutes renvoyées sont les suivantes:

[
    {
        "name": "jim",
        "color": "blue",
        "age": "22"
    },
    {
        "name": "Sam",
        "color": "blue",
        "age": "33"
    },
    {
        "name": "eddie",
        "color": "green",
        "age": "77"
    }
]

Je veux que la _.groupByfonction renvoie un objet qui ressemble à ceci:

[
    {
        color: "blue",
        users: [
            {
                "name": "jim",
                "color": "blue",
                "age": "22"
            },
            {
                "name": "Sam",
                "color": "blue",
                "age": "33"
            }
        ]
    },
    {
        color: "green",
        users: [
            {
                "name": "eddie",
                "color": "green",
                "age": "77"
            }
        ]
    }
]

J'utilise actuellement

_.groupBy(a, function(b) { return b.color})

qui renvoie ceci.

{blue: [{..}], green: [{...}]}

les regroupements sont corrects, mais j'aimerais vraiment ajouter les touches que je veux ( color, users). est-ce possible en utilisant _.groupBy? ou un autre LoDashutilitaire?

Réponses:


141

Vous pouvez le faire comme ça dans Lodash 4.x

var data = [{
  "name": "jim",
  "color": "blue",
  "age": "22"
}, {
  "name": "Sam",
  "color": "blue",
  "age": "33"
}, {
  "name": "eddie",
  "color": "green",
  "age": "77"
}];

console.log(
  _.chain(data)
    // Group the elements of Array based on `color` property
    .groupBy("color")
    // `key` is group's name (color), `value` is the array of objects
    .map((value, key) => ({ color: key, users: value }))
    .value()
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>


Réponse originale

var result = _.chain(data)
    .groupBy("color")
    .pairs()
    .map(function(currentItem) {
        return _.object(_.zip(["color", "users"], currentItem));
    })
    .value();
console.log(result);

Démo en ligne

Remarque: à partir de Lodash 4.0, la .pairsfonction a été renommée_.toPairs()


Très astucieux, mais difficile à comprendre. Pouvez-vous expliquer les étapes intermédiaires, en particulier l'appariement et la fermeture éclair (et le double zip, car _.objectc'est un alias pour _.zipObject).
Benny Bottema

3
lodash 3.10.0 et un peu de journalisation pour chaque étape: jsfiddle.net/plantface/WYCF8/171 . C'est toujours un casse-tête, mais j'y arrive. Je n'ai pas utilisé _.zipet _.pairtellement encore.
Benny Bottema

12
Dans lodash 4.x, la pairs()méthode n'existe plus. Une version lodash 4.0 mise à jour de cet exemple est:.chain(data).groupBy('color') .toPairs().map(function (pair) { return _.zipObject(['Name', 'Suppliers'], air); }).value();
Erik Schierboom

5
J'ai l'impression que loadash devrait avoir une fonction qui fait exactement cela. Je pense que les utilisateurs voudraient regrouper un tableau d'objets par une propriété tout le temps.
Adam Klein

1
L'utilisation _.chainest considérée comme une mauvaise pratique maintenant.
Pawel

90

N'est-ce pas aussi simple?

var result = _(data)
            .groupBy(x => x.color)
            .map((value, key) => ({color: key, users: value}))
            .value();

4
Cela me semble beaucoup plus propre et semble donner les mêmes résultats. Merci!
Jeremy A. West

3
sensationnel. quelle syntaxe est-ce? Première fois que vous voyez que vous pouvez passer le tableau dans le constructeur
Wei-jye

Cela devrait être la réponse acceptée. Simple et propre.
Tiago Stapenhorst Martins le

17

autrement

_.chain(data)
    .groupBy('color')
    .map((users, color) => ({ users, color }))
    .value();

Semblable à la réponse de @ thefourtheye mais un peu plus facile à comprendre
Martin Magakian

Tu es mon héros
AlkanV

17

La réponse la plus élevée utilise la fonction Lodash _.chainqui est considérée comme une mauvaise pratique maintenant "Pourquoi utiliser _.chainest une erreur."

Voici quelques lignes qui abordent le problème du point de vue de la programmation fonctionnelle :

import tap from "lodash/fp/tap";
import flow from "lodash/fp/flow";
import groupBy from "lodash/fp/groupBy";

const map = require('lodash/fp/map').convert({ 'cap': false });

const result = flow(
      groupBy('color'),
      map((users, color) => ({color, users})),
      tap(console.log)
    )(input)

Où se inputtrouve un tableau que vous souhaitez convertir.


J'ai essayé d'utiliser flow()au lieu d' chain()ici, mais la vérification de type dactylographiée devient tout simplement folle avec les fonctions composées. J'espère que nous avons le même niveau de soutien que nous avons actuellement dans RxJS pipe(), par exemple, dans lodash.
BrunoJCM

J'aime beaucoup la syntaxe de votre map (), très cool map((users, color) => ({color, users}))au lieu demap((value, key) => ({ color: key, users: value }))
Gil Epshtain

7

Merci @thefourtheye , votre code a beaucoup aidé. J'ai créé une fonction générique à partir de votre solution en utilisant la version 4.5.0 de Lodash.

function groupBy(dataToGroupOn, fieldNameToGroupOn, fieldNameForGroupName, fieldNameForChildren) {
            var result = _.chain(dataToGroupOn)
             .groupBy(fieldNameToGroupOn)
             .toPairs()
             .map(function (currentItem) {
                 return _.zipObject([fieldNameForGroupName, fieldNameForChildren], currentItem);
             })
             .value();
            return result;
        }

Pour l'utiliser:

var result = groupBy(data, 'color', 'colorId', 'users');

Voici le violoniste mis à jour;

https://jsfiddle.net/sc2L9dby/


5

Voici une version mise à jour utilisant lodash 4 et ES6

const result = _.chain(data)
    .groupBy("color")
    .toPairs()
    .map(pair => _.zipObject(['color', 'users'], pair))
    .value();

2

Je suggérerais une approche différente, en utilisant ma propre bibliothèque, vous pouvez le faire en quelques lignes:

var groupMe = sequence(
  groupBy(pluck('color')),
  forOwn(function(acc, k, v) {
    acc.push({colors: k, users: v});
    return acc;
  },[])
);

var result = groupMe(collection);

Ce serait un peu difficile avec lodash ou Underscore car les arguments sont dans l'ordre inverse, vous devrez donc en utiliser _.partialbeaucoup.


2

Exemple groupBy et somme d'une colonne utilisant Lodash 4.17.4

   var data = [{
                "name": "jim",
                "color": "blue",
                "amount": 22
                }, {
                "name": "Sam",
                "color": "blue",
                "amount": 33
                }, {
               "name": "eddie",
               "color": "green",
               "amount": 77
              }];

      var result = _(data)
                   .groupBy(x => x.color)
                   .map((value, key) => 
                   ({color: key,
                    totalamount: _.sumBy(value,'amount'),
                    users: value})).value();

                    console.log(result);

sympa ... et à jour
Peter van der Lely

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.