використовуючи lodash .groupBy. як додати власні ключі для згрупованого виводу?


104

Ці зразкові дані повернуті з API.

Я використовую Лодаш _.groupByдля перетворення даних у об'єкт, який я можу краще використовувати. Повернені необроблені дані:

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

Я хочу, щоб _.groupByфункція повертала об'єкт, який виглядає приблизно так:

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

В даний час я використовую

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

що це повертає.

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

групування правильні, але я дуже хотів би додати потрібні ключі ( color, users). це можливо за допомогою _.groupBy? чи якась інша LoDashутиліта?

Відповіді:


140

Ви можете зробити це так у 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>


Оригінальний відповідь

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

Демонстрація в Інтернеті

Примітка: Лодаш 4.0 далі, .pairsфункція була перейменована в_.toPairs()


Дуже витончений, але важко обернути голову. Чи можете ви пояснити кроки між ними, особливо спарювання та блискавку (і подвійний блиск, оскільки _.objectце псевдонім для _.zipObject).
Бенні Боттема

3
lodash 3.10.0 та деякі реєстрації для кожного кроку: jsfiddle.net/plantface/WYCF8/171 . Це все ще головоломка, але я туди потрапляю. Не використовував _.zipі _.pairще стільки.
Бенні Боттема

12
У lodash 4.x pairs()метод більше не існує. Оновлена ​​версія цього прикладу lodash 4.0:.chain(data).groupBy('color') .toPairs().map(function (pair) { return _.zipObject(['Name', 'Suppliers'], air); }).value();
Ерік Шербоом

5
Я відчуваю, що loadash повинен мати функцію, яка робить це дуже точно. Я думаю, що користувачі хочуть весь час групувати масив об’єктів за властивістю.
Адам Кляйн

1
_.chainЗараз використання вважається поганою практикою.
Павло

89

Хіба це не просто?

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

4
Мені це здається набагато чистішим і, здається, повертає ті самі результати. Дякую!
Джеремі А. Захід

3
Ого. який це синтаксис? Вперше побачивши, що ви можете передати масив у конструктор
Wei-jye,

Це має бути прийнятою відповіддю. Простий і чистий.
Тіаго Стапенхорст Мартінс


17

Відповідь, що найбільше проголосує, використовує функцію Лодаша, _.chainяка зараз вважається поганою практикою "Чому використовувати _.chainпомилку".

Ось декілька ліній, які підходять до проблеми з точки зору функціонального програмування :

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)

Де inputзнаходиться масив, який ви хочете перетворити.


Я намагався використовувати flow()замість chain()тут, але перевірка типу машинопису просто збожеволіла зі складеними функціями. Я сподіваюся, що ми маємо той самий рівень підтримки, який ми зараз маємо в RxJS pipe(), наприклад, у lodash.
BrunoJCM

Мені дуже подобається ваш синтаксис map (), дуже крутий map((users, color) => ({color, users}))замістьmap((value, key) => ({ color: key, users: value }))
Gil Epshtain

7

Дякуємо @thefourtheye , ваш код дуже допоміг. Я створив загальну функцію з вашого рішення, використовуючи версію 4.5.0 Лодаша.

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

Щоб використовувати його:

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

Ось оновлений фіддер;

https://jsfiddle.net/sc2L9dby/


5

Ось оновлена ​​версія з використанням lodash 4 та ES6

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

2

Я б запропонував інший підхід, використовуючи власну бібліотеку, ви могли це зробити в декількох рядках:

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

var result = groupMe(collection);

З лодашем або підкресленням це буде дещо складно, оскільки аргументи розташовані в протилежному порядку, тому вам доведеться _.partialбагато використовувати .


2

Приклад groupBy та сума стовпця за допомогою 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);

приємно ... та актуально
Пітер ван дер Лелі

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.