przy użyciu lodash .groupBy. jak dodać własne klucze do grupowego wyjścia?


105

Mam te przykładowe dane zwrócone z interfejsu API.

Używam Lodash _.groupBydo konwersji danych na obiekt, którego mogę używać lepiej. Zwrócone nieprzetworzone dane są następujące:

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

Chcę, aby _.groupByfunkcja zwracała obiekt, który wygląda następująco:

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

Obecnie używam

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

który to zwraca.

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

grupowania są poprawne, ale naprawdę chciałbym dodać klucze, które chcę ( color, users). czy jest to możliwe przy użyciu _.groupBy? lub jakieś inne LoDashnarzędzie?

Odpowiedzi:


144

Możesz to zrobić w ten sposób w 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>


Oryginalna odpowiedź

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

Demo online

Uwaga: od wersji Lodash 4.0 nazwa .pairsfunkcji została zmieniona na_.toPairs()


Bardzo fajnie, ale ciężko mi to ogarnąć. Czy możesz wyjaśnić kroki między nimi, zwłaszcza parowanie i pakowanie (i podwójny zamek błyskawiczny, ponieważ _.objectjest aliasem _.zipObject).
Benny Bottema

3
lodash 3.10.0 i trochę logowania dla każdego kroku: jsfiddle.net/plantface/WYCF8/171 . To wciąż zagadka, ale do tego dojdę. Nie używałem _.zipi _.pairjeszcze tak dużo.
Benny Bottema

12
W lodash 4.x pairs()metoda już nie istnieje. Zaktualizowana wersja tego przykładu lodash 4.0 to:.chain(data).groupBy('color') .toPairs().map(function (pair) { return _.zipObject(['Name', 'Suppliers'], air); }).value();
Erik Schierboom

5
Wydaje mi się, że loadash powinien mieć funkcję, która robi dokładnie to. Wydaje mi się, że użytkownicy chcieliby przez cały czas grupować tablicę obiektów według właściwości.
Adam Klein,

1
Używanie _.chainjest obecnie uważane za złą praktykę.
Paweł

90

Czy to nie jest takie proste?

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

4
Wydaje mi się to dużo czystsze i wydaje mi się, że zwraca te same wyniki. Dzięki!
Jeremy A. West

3
łał. jaka to składnia? Po raz pierwszy widzisz, że możesz przekazać tablicę do konstruktora
Wei-jye

To powinna być akceptowana odpowiedź. Proste i czyste.
Tiago Stapenhorst Martins

17

Inny sposób

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

Podobny do @ thefourtheye na odpowiedź, ale nieco łatwiejsze do zrozumienia
Martin Magakian

Jesteś moim bohaterem
AlkanV

17

Najwyższa głosowana odpowiedź wykorzystuje funkcję Lodash, _.chainktóra jest obecnie uważana za złą praktykę „Dlaczego używanie _.chainjest błędem”.

Oto kilka zdań, które podchodzą do problemu z perspektywy programowania funkcjonalnego :

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)

Gdzie inputjest tablica, którą chcesz przekonwertować.


Próbowałem użyć flow()zamiast chain()tutaj, ale sprawdzanie typu maszynopisu po prostu szaleje ze złożonymi funkcjami. Mam nadzieję, że mamy taki sam poziom wsparcia, jaki mamy obecnie w RxJS pipe(), na przykład w lodash.
BrunoJCM

Bardzo podoba mi się twoja składnia map (), bardzo fajna map((users, color) => ({color, users}))zamiastmap((value, key) => ({ color: key, users: value }))
Gil Epshtain

7

Dzięki @thefourtheye , Twój kod bardzo pomógł. Utworzyłem ogólną funkcję z Twojego rozwiązania przy użyciu wersji 4.5.0 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;
        }

Aby z niego skorzystać:

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

Oto zaktualizowany skrzypek;

https://jsfiddle.net/sc2L9dby/


5

Oto zaktualizowana wersja wykorzystująca lodash 4 i ES6

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

2

Sugerowałbym inne podejście, korzystając z mojej własnej biblioteki, możesz to zrobić w kilku wierszach:

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

var result = groupMe(collection);

Byłoby to trochę trudne w przypadku lodash lub podkreślenia, ponieważ argumenty są w odwrotnej kolejności, więc musiałbyś dużo używać _.partial.


2

Przykład groupBy i suma kolumny przy użyciu 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);

ładne ... i aktualne
Peter van der Lely

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.