使用 Array.reduce() 通过多个键对数组进行分组
Posted
技术标签:
【中文标题】使用 Array.reduce() 通过多个键对数组进行分组【英文标题】:Grouping an array by multiple keys with Array.reduce() 【发布时间】:2022-01-11 18:04:51 【问题描述】:第一次写到这里,遇到如下问题。例如,我有以下数组:
const input = [
id: 1,
date: "01-01-2021",
source: "TT",
metrics: conversions: 10, cpl: 3 ,
,
id: 2,
date: "01-01-2021",
source: "TT",
metrics: conversions: 15, cpl: 3 ,
,
id: 3,
date: "01-01-2021",
source: "FB",
metrics: conversions: 15, cpl: 4 ,
,
id: 4,
date: "01-01-2021",
source: "FB",
metrics: conversions: 15, cpl: 4 ,
,
id: 5,
date: "02-01-2021",
source: "TT",
metrics: conversions: 5, cpl: 2 ,
,
id: 6,
date: "02-01-2021",
source: "TT",
metrics: conversions: 15, cpl: 2 ,
,
id: 7,
date: "02-01-2021",
source: "FB",
metrics: conversions: 25, cpl: 1 ,
,
id: 8,
date: "02-01-2021",
source: "FB",
metrics: conversions: 30, cpl: 1 ,
,
];
我需要得到一个按日期和来源分组的数组,其值将是特定日期的所有值的总和,例如如下结果:
const output = [
date: "01-01-2021",
TT: 25,
FB: 30,
,
date: "02-01-2021",
TT: 20,
FB: 55,
,
];
在我的解决方案中,我找到了唯一的键和日期,但不知道下一步该做什么。你能帮助我吗?示例代码:
const result = input.reduce((acc, current) =>
const dateItem = acc.find((item) => item.date === current.date);
const sources = input.map((item) => item.source).filter((value, index, self) => self.indexOf(value) === index);
if (dateItem)
return [...acc.filter((i) => i.date !== current.date), ...dateItem ];
return [...acc, date: current.date ];
, []);
【问题讨论】:
请解释一下将输入转化为输出的具体逻辑,这里不清楚。 【参考方案1】:Array.reduce
和 Object.values
将给出结果。
const input = [
id: 1, date: "01-01-2021", source: "TT", metrics: conversions: 10, cpl: 3 , ,
id: 2, date: "01-01-2021", source: "TT", metrics: conversions: 15, cpl: 3 , ,
id: 3, date: "01-01-2021", source: "FB", metrics: conversions: 15, cpl: 4 , ,
id: 4, date: "01-01-2021", source: "FB", metrics: conversions: 15, cpl: 4 , ,
id: 5, date: "02-01-2021", source: "TT", metrics: conversions: 5, cpl: 2 , ,
id: 6, date: "02-01-2021", source: "TT", metrics: conversions: 15, cpl: 2 , ,
id: 7, date: "02-01-2021", source: "FB", metrics: conversions: 25, cpl: 1 , ,
id: 8, date: "02-01-2021", source: "FB", metrics: conversions: 30, cpl: 1 , ,
];
const output = input.reduce((acc, curr) =>
if (acc[curr.date])
acc[curr.date][curr.source] = (acc[curr.date][curr.source] || 0) + curr.metrics.conversions;
else
acc[curr.date] =
date: curr.date,
[curr.source]: curr.metrics.conversions
return acc;
, );
console.log(Object.values(output));
【讨论】:
【参考方案2】:使用日期作为键的简单化简循环。全部组合后,就可以使用值来获取数组了。
const input = [
id: 1,
date: "01-01-2021",
source: "TT",
metrics:
conversions: 10,
cpl: 3
,
,
id: 2,
date: "01-01-2021",
source: "TT",
metrics:
conversions: 15,
cpl: 3
,
,
id: 3,
date: "01-01-2021",
source: "FB",
metrics:
conversions: 15,
cpl: 4
,
,
id: 4,
date: "01-01-2021",
source: "FB",
metrics:
conversions: 15,
cpl: 4
,
,
id: 5,
date: "02-01-2021",
source: "TT",
metrics:
conversions: 5,
cpl: 2
,
,
id: 6,
date: "02-01-2021",
source: "TT",
metrics:
conversions: 15,
cpl: 2
,
,
id: 7,
date: "02-01-2021",
source: "FB",
metrics:
conversions: 25,
cpl: 1
,
,
id: 8,
date: "02-01-2021",
source: "FB",
metrics:
conversions: 30,
cpl: 1
,
,
];
const results = Object.values(input.reduce((o, data) =>
o[data.date] = o[data.date] || date: data.date ;
o[data.date][data.source] = (o[data.date][data.source] || 0) + data.metrics.conversions;
return o;
, ));
console.log(results);
【讨论】:
非常感谢,我设法在您的解决方案中添加了日期属性,一切正常。对不起我的英语 应该Object.values(...)
是Object.entries(...).map( [date,vals] => (date,...vals) )
?
哎呀漏掉了o[data.date] = o[data.date] || date: data.date ;
是的,我写了同一行。谢谢以上是关于使用 Array.reduce() 通过多个键对数组进行分组的主要内容,如果未能解决你的问题,请参考以下文章
javascript 使用array.reduce添加减号加数字