using lodash .groupBy. Wie füge ich meine eigenen Schlüssel für die gruppierte Ausgabe hinzu?

104

Ich habe diese Beispieldaten von einer API zurückgegeben.

Ich verwende Lodashs _.groupBy, um die Daten in ein Objekt zu konvertieren, das ich besser verwenden kann. Die zurückgegebenen Rohdaten lauten wie folgt:

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

Ich möchte, dass die _.groupByFunktion ein Objekt zurückgibt, das so aussieht:

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

Zur Zeit benutze ich

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

was dies zurückgibt.

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

Die Gruppierungen sind korrekt, aber ich möchte wirklich die gewünschten Schlüssel hinzufügen ( color, users). ist das möglich mit _.groupBy? oder ein anderes LoDashDienstprogramm?

user1767105
quelle

Antworten:

140

Sie können dies in Lodash 4.x so tun

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>


Ursprüngliche Antwort

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

Online-Demo

Hinweis: Ab Lodash 4.0 wurde die .pairsFunktion in umbenannt_.toPairs()

thefourtheye
quelle
Sehr geschickt, aber schwer, meinen Kopf herumzuwickeln. Können Sie die Schritte dazwischen erklären, insbesondere das Pairing und Zippen (und die doppelte Zip, da dies _.objectein Alias ​​für ist _.zipObject).
Benny Bottema
3
lodash 3.10.0 und einige Protokollierungen für jeden Schritt: jsfiddle.net/plantface/WYCF8/171 . Es ist immer noch ein Rätsel, aber ich komme dorthin. Noch nicht benutzt _.zipund _.pairso viel.
Benny Bottema
12
In lodash 4.x existiert die pairs()Methode nicht mehr. Eine aktualisierte lodash 4.0-Version dieses Beispiels ist:.chain(data).groupBy('color') .toPairs().map(function (pair) { return _.zipObject(['Name', 'Suppliers'], air); }).value();
Erik Schierboom
5
Ich denke, Loadash sollte eine Funktion haben, die genau das tut. Ich würde denken, dass Benutzer die ganze Zeit ein Array von Objekten nach einer Eigenschaft gruppieren möchten.
Adam Klein
1
Die Verwendung _.chainwird derzeit als schlechte Praxis angesehen.
Pawel
88

Ist es nicht so einfach?

var result = _(data)
            .groupBy(x => x.color)
            .map((value, key) => ({color: key, users: value}))
            .value();
Darragh
quelle
4
Dies scheint mir viel sauberer zu sein und scheint die gleichen Ergebnisse zu liefern. Vielen Dank!
Jeremy A. West
3
Beeindruckend. Welche Syntax ist das? Zum ersten Mal sehen, dass Sie das Array an den Konstruktor übergeben können
Wei-jye
Dies sollte die akzeptierte Antwort sein. Einfach und sauber.
Tiago Stapenhorst Martins
17

ein anderer Weg

_.chain(data)
    .groupBy('color')
    .map((users, color) => ({ users, color }))
    .value();
stasovlas
quelle
Ähnlich wie die Antwort von @ thefourtheye, aber etwas leichter zu verstehen
Martin Magakian
Du bist mein Held
AlkanV
17

Die Antwort mit der höchsten Bewertung_.chain verwendet die Lodash- Funktion, die derzeit als schlechte Praxis angesehen wird. "Warum ist die Verwendung ein Fehler ? "_.chain

Hier ist ein paar Zeilen, die sich dem Problem aus Sicht der funktionalen Programmierung nähern :

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)

Wo inputist ein Array, das Sie konvertieren möchten?

Pawel
quelle
Ich habe versucht, flow()anstelle von chain()hier zu verwenden, aber die Typprüfung von Typoskript wird mit komponierten Funktionen einfach verrückt. Ich hoffe, wir haben die gleiche Unterstützung, die wir derzeit bei RxJS haben pipe(), zum Beispiel bei lodash.
BrunoJCM
Ich mag deine map () - Syntax sehr, sehr cool map((users, color) => ({color, users}))stattmap((value, key) => ({ color: key, users: value }))
Gil Epshtain
7

Vielen Dank an @thefourtheye , Ihr Code hat sehr geholfen. Ich habe aus Ihrer Lösung eine generische Funktion mit der Version 4.5.0 von Lodash erstellt.

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

Um es zu benutzen:

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

Hier ist der aktualisierte Geiger;

https://jsfiddle.net/sc2L9dby/

Andrew
quelle
5

Hier ist eine aktualisierte Version mit lodash 4 und ES6

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

Ich würde einen anderen Ansatz vorschlagen. Wenn Sie meine eigene Bibliothek verwenden, können Sie dies in wenigen Zeilen tun:

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

var result = groupMe(collection);

Dies wäre bei lodash oder Underscore etwas schwierig, da die Argumente in der entgegengesetzten Reihenfolge angeordnet sind und Sie daher _.partialviel verwenden müssten .

elclanrs
quelle
2

Beispiel groupBy und Summe einer Spalte mit 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
quelle
schön ... und auf dem neuesten Stand
Peter van der Lely
-2

Im Jahr 2017 tun Sie dies

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