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?

user1767105
la source

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()

thefourtheye
la source
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();
Darragh
la source
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();
stasovlas
la source
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.

Pawel
la source
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/

Andrew
la source
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();
Matthieu
la source
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.

elclans
la source
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);
Iyyappan Amirthalingam
la source
sympa ... et à jour
Peter van der Lely
-2

En 2017, faites-le

_.chain(data)
  .groupBy("color")
  .toPairs()
  .map(item => _.zipObject(["color", "users"], item))
  .value();
Владислав Сироштан
la source