โดยใช้ lodash .groupBy จะเพิ่มคีย์ของคุณเองสำหรับเอาต์พุตที่จัดกลุ่มได้อย่างไร?


106

ฉันมีข้อมูลตัวอย่างที่ส่งคืนจาก API

ฉันใช้ Lodash _.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ยูทิลิตี้อื่น ๆ?

คำตอบ:


145

คุณสามารถทำได้เช่นนี้ใน 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);

การสาธิตออนไลน์

หมายเหตุ: Lodash 4.0 เป็นต้นไป.pairsฟังก์ชันถูกเปลี่ยนชื่อเป็น_.toPairs()


ดีมาก แต่ยากที่จะห่อหัวของฉันไปรอบ ๆ คุณช่วยอธิบายขั้นตอนระหว่างนี้ได้ไหมโดยเฉพาะการจับคู่และการซิป (และซิปสองชั้นเนื่องจาก_.objectเป็นนามแฝง_.zipObject)
Benny Bottema

3
lodash 3.10.0 และการตัดไม้บางอย่างสำหรับทุกขั้นตอน: jsfiddle.net/plantface/WYCF8/171 มันยังคงเป็นปริศนา แต่ฉันกำลังไปถึงจุดนั้น ยังไม่ได้ใช้_.zipและ_.pairยังมาก
Benny Bottema

12
ใน lodash 4.x pairs()วิธีนี้ไม่มีอยู่อีกต่อไป ตัวอย่างเวอร์ชัน lodash 4.0 ที่อัปเดตคือ:.chain(data).groupBy('color') .toPairs().map(function (pair) { return _.zipObject(['Name', 'Suppliers'], air); }).value();
Erik Schierboom

5
ฉันรู้สึกว่า loadash ควรมีฟังก์ชันที่ทำสิ่งนี้ได้แน่นอน ฉันคิดว่าผู้ใช้ต้องการจัดกลุ่มอาร์เรย์ของวัตถุตามคุณสมบัติตลอดเวลา
Adam Klein

1
การใช้_.chainถือเป็นการปฏิบัติที่ไม่ดีในขณะนี้
Pawel

90

มันไม่ง่ายอย่างนี้เหรอ?

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

4
สิ่งนี้ดูเหมือนจะสะอาดกว่าสำหรับฉันมากและดูเหมือนว่าจะส่งคืนผลลัพธ์เดียวกัน ขอบคุณ!
Jeremy A. West

3
ว้าว. ไวยากรณ์คืออะไร? ครั้งแรกที่เห็นว่าคุณสามารถส่งอาร์เรย์ไปยังตัวสร้างได้
Wei-jye

นี่ควรเป็นคำตอบที่ได้รับการยอมรับ เรียบง่ายและสะอาด
Tiago Stapenhorst Martins

17

อีกวิธีหนึ่ง

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

คล้ายกับคำตอบของ @ thefourtheye แต่เข้าใจง่ายกว่านิดหน่อย
Martin Magakian

คุณคือฮีโร่ของฉัน
AlkanV

17

คำตอบที่ได้รับการโหวตสูงสุดใช้ฟังก์ชันLodash _.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()นี่ แต่การตรวจสอบประเภทของ typescript นั้นบ้าคลั่งไปกับฟังก์ชันประกอบ ฉันหวังว่าเราจะได้รับการสนับสนุนในระดับเดียวกับที่เรามีใน RxJS ในปัจจุบันpipe()เช่นใน lodash
BrunoJCM

ฉันชอบไวยากรณ์แผนที่ () ของคุณเจ๋งมากmap((users, color) => ({color, users}))แทนmap((value, key) => ({ color: key, users: value }))
Gil Epshtain

7

ขอบคุณ@thefourtheyeรหัสของคุณช่วยได้มาก ฉันสร้างฟังก์ชันทั่วไปจากโซลูชันของคุณโดยใช้ Lodash เวอร์ชัน 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);

การใช้ lodash หรือ Underscore จะยากสักหน่อยเพราะอาร์กิวเมนต์อยู่ในลำดับที่ตรงกันข้ามกันดังนั้นคุณต้องใช้_.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);

ดี ... และข้อมูลล่าสุด
Peter van der Lely

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.