bằng cách sử dụng lodash .groupBy. làm thế nào để thêm các khóa của riêng bạn cho đầu ra được nhóm?


104

Tôi có dữ liệu mẫu này được trả về từ một API.

Tôi đang sử dụng Lodash _.groupByđể chuyển đổi dữ liệu thành một đối tượng mà tôi có thể sử dụng tốt hơn. Dữ liệu thô được trả về là:

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

Tôi muốn _.groupByhàm trả về một đối tượng giống như sau:

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

Hiện tại tôi đang sử dụng

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

đang trả lại điều này.

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

các nhóm là chính xác, nhưng tôi thực sự muốn thêm các khóa tôi muốn ( color, users). cái này có thể sử dụng được _.groupBykhông? hoặc một số LoDashtiện ích khác ?

Câu trả lời:


140

Bạn có thể làm điều đó như thế này trong 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>


Câu trả lời gốc

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

Demo trực tuyến

Lưu ý: Lodash 4.0 trở đi, .pairshàm đã được đổi tên thành_.toPairs()


Rất tiện lợi, nhưng khó để quấn lấy đầu tôi. Bạn có thể giải thích các bước ở giữa, đặc biệt là ghép nối và nén (và zip kép, vì _.objectlà bí danh cho _.zipObject).
Benny Bottema,

3
lodash 3.10.0 và một số ghi nhật ký cho mỗi bước: jsfiddle.net/plantface/WYCF8/171 . Nó vẫn còn là một câu đố, nhưng tôi sẽ đến đó. Chưa được sử dụng _.zip_.pairrất nhiều.
Benny Bottema,

12
Trong lodash 4.x, pairs()phương thức này không tồn tại nữa. Phiên bản lodash 4.0 được cập nhật của ví dụ này là:.chain(data).groupBy('color') .toPairs().map(function (pair) { return _.zipObject(['Name', 'Suppliers'], air); }).value();
Erik Schierboom

5
Tôi cảm thấy như loadash nên có một chức năng thực hiện điều này rất chính xác. Tôi nghĩ rằng người dùng luôn muốn nhóm một mảng các đối tượng theo một thuộc tính.
Adam Klein

1
Sử dụng _.chainđược coi là một thực hành xấu bây giờ.
Pawel

88

Nó không phải là nó đơn giản?

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

4
Điều này có vẻ rõ ràng hơn nhiều đối với tôi và dường như đang trả lại kết quả tương tự. Cảm ơn!
Jeremy A. West

3
ồ. cú pháp này là gì? Lần đầu tiên nhìn thấy rằng bạn có thể vượt qua mảng vào constructor
Wei-Jye

Đây phải là câu trả lời được chấp nhận. Đơn giản và sạch sẽ.
Tiago Stapenhorst Martins

17

cách khác

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

Tương tự như @ thefourtheye của câu trả lời nhưng một chút dễ dàng hơn để hiểu
Martin Magakian

Bạn là người hùng của tôi
AlkanV

17

Câu trả lời được bình chọn cao nhất sử dụng hàm Lodash _.chainđược coi là một phương pháp không tốt hiện nay "Tại sao sử dụng_.chain là một sai lầm."

Dưới đây là một vài dòng tiếp cận vấn đề từ góc độ lập trình hàm :

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)

Đâu inputlà một mảng mà bạn muốn chuyển đổi.


Tôi đã cố gắng sử dụng flow()thay vì chain()ở đây, nhưng việc kiểm tra kiểu của typecript chỉ đơn giản là trở nên điên rồ với các hàm đã soạn. Tôi hy vọng chúng tôi có cùng mức hỗ trợ mà chúng tôi hiện có đối với RxJS pipe(), chẳng hạn như ở lodash.
BrunoJCM

Tôi thực sự thích cú pháp map () của bạn, rất thú vị map((users, color) => ({color, users}))thay vìmap((value, key) => ({ color: key, users: value }))
Gil Epshtain

7

Cảm ơn @thefourtheye , mã của bạn đã giúp ích rất nhiều. Tôi đã tạo một hàm chung từ giải pháp của bạn bằng cách sử dụng phiên bản 4.5.0 của 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;
        }

Để dùng nó:

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

Đây là cập nhật fiddler;

https://jsfiddle.net/sc2L9dby/


5

Đây là phiên bản cập nhật sử dụng lodash 4 và ES6

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

2

Tôi sẽ đề xuất một cách tiếp cận khác, sử dụng thư viện của riêng tôi, bạn có thể thực hiện việc này trong một vài dòng:

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

var result = groupMe(collection);

Điều này sẽ hơi khó khăn với lodash hoặc Underscore vì các đối số theo thứ tự ngược lại, vì vậy bạn sẽ phải sử dụng _.partialnhiều.


2

Ví dụ nhómBy và tổng của một cột bằng 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);

đẹp ... và cập nhật
Peter van der Lely

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.