使用 lodash .groupBy。如何为分组输出添加自己的键?

Posted

技术标签:

【中文标题】使用 lodash .groupBy。如何为分组输出添加自己的键?【英文标题】:using lodash .groupBy. how to add your own keys for grouped output? 【发布时间】:2014-06-29 08:03:03 【问题描述】:

我有这个从 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: [...]

分组是正确的,但我真的很想添加我想要的键(colorusers)。这可以使用_.groupBy 吗?或其他一些LoDash 实用程序?

【问题讨论】:

【参考方案1】:

在 Underscore 和 Lodash(3.x 和 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);

Online Demo

注意: Lodash 4.0 起,.pairs 函数已重命名为 _.toPairs()

【讨论】:

非常漂亮,但难以理解。你能解释一下中间的步骤吗,尤其是配对和拉链(以及双拉链,因为_.object_.zipObject 的别名)。 lodash 3.10.0 以及每一步的一些日志记录:jsfiddle.net/plantface/WYCF8/171。这仍然是一个谜,但我正在到达那里。还没用过_.zip_.pair 在 lodash 4.x 中,pairs() 方法不再存在。此示例的更新 lodash 4.0 版本是:.chain(data).groupBy('color') .toPairs().map(function (pair) return _.zipObject(['Name', 'Suppliers'], air); ).value(); 我觉得 loadash 应该有一个功能来做这个非常精确的事情。我认为用户总是希望按属性对一组对象进行分组。 现在使用_.chain 被认为是一种不好的做法。【参考方案2】:

使用lodash,其他答案看起来不错。

我会建议使用 javascript 的不同方法,例如 Array#reduceobject for storing??= 语法。结果,它只需要O(n) 时间复杂度。

使用reduce 聚合数据。 仅当acc[color] 为nullish (null or undefined) 时才使用logical nullish assignment

const data = [ "name": "jim","color": "blue","age": "22","name": "Sam", "color": "blue", "age": "33" ,  "name":"eddie","color": "green","age": "77"];

const result = data.reduce((acc, name, color, age) => 
 acc[color] ??= color: color, users: [];
 acc[color].users.push(name, color, age);
 
 return acc;
, );
console.log(Object.values(result));

【讨论】:

【参考方案3】:

最高投票的答案使用 Lodash _.chain 函数,现在被认为是一种不好的做法 "Why using _.chain is a mistake."

这里有一些从函数式编程角度解决问题的方法:

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 中。 我真的很喜欢你的 map() 语法,非常酷的 map((users, color) => (color, users)) 而不是 map((value, key) => ( color: key, users: value )) 防止treeshaking的问题只适用于Lodash。在 Underscore 中,您可以自定义从 1.11 版本开始将哪些函数混入 _【参考方案4】:

另一种方式

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

【讨论】:

类似于@thefourtheye 的回答,但更容易理解【参考方案5】:

2017 年这样做

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

【讨论】:

【参考方案6】:

感谢@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/

【讨论】:

【参考方案7】:

使用 Lodash 4.17.4 的示例 groupBy 和列的总和

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

【讨论】:

【参考方案8】:

这是使用 lodash 4 和 ES6 的更新版本

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

【讨论】:

【参考方案9】:

是不是很简单?

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

【讨论】:

这对我来说似乎更干净,并且似乎返回了相同的结果。谢谢! 哇。这是什么语法?第一次看到可以将数组传递给构造函数【参考方案10】:

我会建议一种不同的方法,使用 my own library 你可以在几行中做到这一点:

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

【讨论】:

以上是关于使用 lodash .groupBy。如何为分组输出添加自己的键?的主要内容,如果未能解决你的问题,请参考以下文章

_.groupBy momentjs格式返回键未定义

lodash groupby 使用字符串键而不是数字

如何为 Laravel ORM 中每个组中的单个项目执行 groupBy()

如何为分组表部分设置不同的背景图像..?

如何为 GraphQL 使用数组模式类型

如何为 size() 列分配名称?