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?

user1767105
źródło

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

na czworo
źródło
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();
Darragh
źródło
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();
stasovlas
źródło
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ć.

Paweł
źródło
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/

Andrzej
źródło
5

Oto zaktualizowana wersja wykorzystująca lodash 4 i ES6

const result = _.chain(data)
    .groupBy("color")
    .toPairs()
    .map(pair => _.zipObject(['color', 'users'], pair))
    .value();
Mateusz
źródło
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.

elclanrs
źródło
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);
Iyyappan Amirthalingam
źródło
ładne ... i aktualne
Peter van der Lely
-2

Zrób to w 2017 roku

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