使用 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: [...]
分组是正确的,但我真的很想添加我想要的键(color
、users
)。这可以使用_.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#reduce
、object 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。如何为分组输出添加自己的键?的主要内容,如果未能解决你的问题,请参考以下文章