如何对数组条目进行分组和合并以及对多个公共(但不是全部)键的值求和?
How to group and merge array entries and to sum-up values on multiple common (but not all) keys?
这个 thread 有多种方法可以按公共键对值求和,并且有一种方法可以按所有公共键进行分组。我正在寻找更精细和受控的分组。我的数据示例如下:
const arr = [
{'ID':'1','Parent':'1','Member': '1','Code': '123','Subject': 'Org A','value': 0.3},
{'ID':'2','Parent':'1','Member': '1','Code': '124','Subject': 'Org A','value': 0.25},
{'ID':'3','Parent':'1','Member': '1','Code': '123','Subject': 'Org B','value': 0.45},
{'ID':'4','Parent':'1','Member': '2','Code': '125','Subject': 'Org A','value': 0.8},
{'ID':'5','Parent':'1','Member': '2','Code': '211','Subject': 'Org C','value': 0.3},
{'ID':'6','Parent':'1','Member': '3','Code': '221','Subject': 'Org B','value': 0.3},
{'ID':'7','Parent':'1','Member': '3','Code': '221','Subject': 'Org C','value': 0.25},
{'ID':'8','Parent':'1','Member': '3','Code': '234','Subject': 'Org A','value': 0.45},
{'ID':'9','Parent':'1','Member': '4','Code': '123','Subject': 'Org A','value': 0.8},
{'ID':'10','Parent':'2','Member': '5','Code': '123','Subject': 'Org D','value': 0.3},
{'ID':'11','Parent':'2','Member': '5','Code': '123','Subject': 'Org E','value': 0.3},
{'ID':'12','Parent':'2','Member': '6','Code': '125','Subject': 'Org E','value': 0.25},
{'ID':'13','Parent':'2','Member': '6','Code': '211','Subject': 'Org F','value': 0.45},
{'ID':'14','Parent':'2','Member': '6','Code': '221','Subject': 'Org F','value': 0.8},
{'ID':'15','Parent':'2','Member': '6','Code': '123','Subject': 'Org G','value': 0.3},
{'ID':'16','Parent':'3','Member': '7','Code': '124','Subject': 'Org H','value': 0.3},
{'ID':'17','Parent':'3','Member': '8','Code': '124','Subject': 'Org H','value': 0.25},
{'ID':'18','Parent':'3','Member': '9','Code': '123','Subject': 'Org I','value': 0.45},
{'ID':'19','Parent':'3','Member': '10','Code': '123','Subject': 'Org J','value': 0.8},
{'ID':'20','Parent':'3','Member': '10','Code': '211','Subject': 'Org I','value': 0.3},
{'ID':'21','Parent':'4','Member': '11','Code': '221','Subject': 'Org K','value': 0.3},
{'ID':'22','Parent':'4','Member': '11','Code': '234','Subject': 'Org K','value': 0.25},
{'ID':'23','Parent':'4','Member': '12','Code': '234','Subject': 'Org K','value': 0.45},
{'ID':'24','Parent':'4','Member': '12','Code': '123','Subject': 'Org L','value': 0.8},
{'ID':'25','Parent':'4','Member': '13','Code': '211','Subject': 'Org M','value': 0.3}
];
来自其他线程的解决方案按 1 组列分组:
// Group by 1 column //
const summed = arr.reduce((acc, cur) => {
const item = acc.length > 0 && acc.find(({
Code
}) => Code === cur.Code)
if (item) {
item.value += cur.value
} else acc.push({Code:cur.Code,value:cur.value});
return acc
}, [])
console.log(arr); // not modified
console.log(summed)
或按所有常用值
// Group by multiple columns //
const res = Array.from(arr.reduce((acc, {value, ...r}) => {
const key = JSON.stringify(r);
const current = acc.get(key) || {...r, value: 0};
return acc.set(key, {...current, value: current.value + value});
}, new Map).values());
console.log(res);
我正在尝试按父级和代码分组以对值求和。
只需在 find()
回调中测试这两个属性,并在推入 acc
时将它们添加到新对象中。
const arr = [
{'ID':'1','Parent':'1','Member': '1','Code': '123','Subject': 'Org A','value': 0.3},
{'ID':'2','Parent':'1','Member': '1','Code': '124','Subject': 'Org A','value': 0.25},
{'ID':'3','Parent':'1','Member': '1','Code': '123','Subject': 'Org B','value': 0.45},
{'ID':'4','Parent':'1','Member': '2','Code': '125','Subject': 'Org A','value': 0.8},
{'ID':'5','Parent':'1','Member': '2','Code': '211','Subject': 'Org C','value': 0.3},
{'ID':'6','Parent':'1','Member': '3','Code': '221','Subject': 'Org B','value': 0.3},
{'ID':'7','Parent':'1','Member': '3','Code': '221','Subject': 'Org C','value': 0.25},
{'ID':'8','Parent':'1','Member': '3','Code': '234','Subject': 'Org A','value': 0.45},
{'ID':'9','Parent':'1','Member': '4','Code': '123','Subject': 'Org A','value': 0.8},
{'ID':'10','Parent':'2','Member': '5','Code': '123','Subject': 'Org D','value': 0.3},
{'ID':'11','Parent':'2','Member': '5','Code': '123','Subject': 'Org E','value': 0.3},
{'ID':'12','Parent':'2','Member': '6','Code': '125','Subject': 'Org E','value': 0.25},
{'ID':'13','Parent':'2','Member': '6','Code': '211','Subject': 'Org F','value': 0.45},
{'ID':'14','Parent':'2','Member': '6','Code': '221','Subject': 'Org F','value': 0.8},
{'ID':'15','Parent':'2','Member': '6','Code': '123','Subject': 'Org G','value': 0.3},
{'ID':'16','Parent':'3','Member': '7','Code': '124','Subject': 'Org H','value': 0.3},
{'ID':'17','Parent':'3','Member': '8','Code': '124','Subject': 'Org H','value': 0.25},
{'ID':'18','Parent':'3','Member': '9','Code': '123','Subject': 'Org I','value': 0.45},
{'ID':'19','Parent':'3','Member': '10','Code': '123','Subject': 'Org J','value': 0.8},
{'ID':'20','Parent':'3','Member': '10','Code': '211','Subject': 'Org I','value': 0.3},
{'ID':'21','Parent':'4','Member': '11','Code': '221','Subject': 'Org K','value': 0.3},
{'ID':'22','Parent':'4','Member': '11','Code': '234','Subject': 'Org K','value': 0.25},
{'ID':'23','Parent':'4','Member': '12','Code': '234','Subject': 'Org K','value': 0.45},
{'ID':'24','Parent':'4','Member': '12','Code': '123','Subject': 'Org L','value': 0.8},
{'ID':'25','Parent':'4','Member': '13','Code': '211','Subject': 'Org M','value': 0.3}
];
const summed = arr.reduce((acc, cur) => {
const item = acc.length > 0 && acc.find(({
Code, Parent
}) => Code === cur.Code && Parent == cur.Parent)
if (item) {
item.value += cur.value
} else acc.push({
Code: cur.Code,
Parent: cur.Parent,
value: cur.value
});
return acc
}, [])
console.log(arr); // not modified
console.log(summed)
根据我上面的评论...
The OP might find an answer in the entirely generic implemented approach posted as a solution to this recently asked question ...
function groupMergeAndAggregateGenerically(collector, item) {
const {
createKey, createMerger, aggregate,
lookup, result = [],
} = collector;
const key = createKey(item);
let merger = lookup.get(key) ?? null;
if (merger === null) {
merger = createMerger(item);
lookup.set(key, merger);
result.push(merger);
}
aggregate(merger, item);
return collector;
}
const arr = [
{ 'ID':'1','Parent':'1','Member': '1','Code': '123','Subject': 'Org A','value': 0.3 },
{ 'ID':'2','Parent':'1','Member': '1','Code': '124','Subject': 'Org A','value': 0.25 },
{ 'ID':'3','Parent':'1','Member': '1','Code': '123','Subject': 'Org B','value': 0.45 },
{ 'ID':'4','Parent':'1','Member': '2','Code': '125','Subject': 'Org A','value': 0.8 },
{ 'ID':'5','Parent':'1','Member': '2','Code': '211','Subject': 'Org C','value': 0.3 },
{ 'ID':'6','Parent':'1','Member': '3','Code': '221','Subject': 'Org B','value': 0.3 },
{ 'ID':'7','Parent':'1','Member': '3','Code': '221','Subject': 'Org C','value': 0.25 },
{ 'ID':'8','Parent':'1','Member': '3','Code': '234','Subject': 'Org A','value': 0.45 },
{ 'ID':'9','Parent':'1','Member': '4','Code': '123','Subject': 'Org A','value': 0.8 },
{ 'ID':'10','Parent':'2','Member': '5','Code': '123','Subject': 'Org D','value': 0.3 },
{ 'ID':'11','Parent':'2','Member': '5','Code': '123','Subject': 'Org E','value': 0.3 },
{ 'ID':'12','Parent':'2','Member': '6','Code': '125','Subject': 'Org E','value': 0.25 },
{ 'ID':'13','Parent':'2','Member': '6','Code': '211','Subject': 'Org F','value': 0.45 },
{ 'ID':'14','Parent':'2','Member': '6','Code': '221','Subject': 'Org F','value': 0.8 },
{ 'ID':'15','Parent':'2','Member': '6','Code': '123','Subject': 'Org G','value': 0.3 },
{ 'ID':'16','Parent':'3','Member': '7','Code': '124','Subject': 'Org H','value': 0.3 },
{ 'ID':'17','Parent':'3','Member': '8','Code': '124','Subject': 'Org H','value': 0.25 },
{ 'ID':'18','Parent':'3','Member': '9','Code': '123','Subject': 'Org I','value': 0.45 },
{ 'ID':'19','Parent':'3','Member': '10','Code': '123','Subject': 'Org J','value': 0.8 },
{ 'ID':'20','Parent':'3','Member': '10','Code': '211','Subject': 'Org I','value': 0.3 },
{ 'ID':'21','Parent':'4','Member': '11','Code': '221','Subject': 'Org K','value': 0.3 },
{ 'ID':'22','Parent':'4','Member': '11','Code': '234','Subject': 'Org K','value': 0.25 },
{ 'ID':'23','Parent':'4','Member': '12','Code': '234','Subject': 'Org K','value': 0.45 },
{ 'ID':'24','Parent':'4','Member': '12','Code': '123','Subject': 'Org L','value': 0.8 },
{ 'ID':'25','Parent':'4','Member': '13','Code': '211','Subject': 'Org M','value': 0.3 },
];
const { result: mergedData } = arr
.reduce(groupMergeAndAggregateGenerically, {
// OP: "I am trying to group by Parent and Code ..."
createKey: ({ Parent, Code }) => [Parent, Code].join('_'),
createMerger: ({ Parent, Code }) => ({ Parent, Code, value: 0 }),
// OP: "[and] ... to sum the value."
aggregate: (merger, { value }) => merger.value += value,
lookup: new Map,
result: [],
});
console.log({ mergedData });
.as-console-wrapper { min-height: 100%!important; top: 0; }
这个 thread 有多种方法可以按公共键对值求和,并且有一种方法可以按所有公共键进行分组。我正在寻找更精细和受控的分组。我的数据示例如下:
const arr = [
{'ID':'1','Parent':'1','Member': '1','Code': '123','Subject': 'Org A','value': 0.3},
{'ID':'2','Parent':'1','Member': '1','Code': '124','Subject': 'Org A','value': 0.25},
{'ID':'3','Parent':'1','Member': '1','Code': '123','Subject': 'Org B','value': 0.45},
{'ID':'4','Parent':'1','Member': '2','Code': '125','Subject': 'Org A','value': 0.8},
{'ID':'5','Parent':'1','Member': '2','Code': '211','Subject': 'Org C','value': 0.3},
{'ID':'6','Parent':'1','Member': '3','Code': '221','Subject': 'Org B','value': 0.3},
{'ID':'7','Parent':'1','Member': '3','Code': '221','Subject': 'Org C','value': 0.25},
{'ID':'8','Parent':'1','Member': '3','Code': '234','Subject': 'Org A','value': 0.45},
{'ID':'9','Parent':'1','Member': '4','Code': '123','Subject': 'Org A','value': 0.8},
{'ID':'10','Parent':'2','Member': '5','Code': '123','Subject': 'Org D','value': 0.3},
{'ID':'11','Parent':'2','Member': '5','Code': '123','Subject': 'Org E','value': 0.3},
{'ID':'12','Parent':'2','Member': '6','Code': '125','Subject': 'Org E','value': 0.25},
{'ID':'13','Parent':'2','Member': '6','Code': '211','Subject': 'Org F','value': 0.45},
{'ID':'14','Parent':'2','Member': '6','Code': '221','Subject': 'Org F','value': 0.8},
{'ID':'15','Parent':'2','Member': '6','Code': '123','Subject': 'Org G','value': 0.3},
{'ID':'16','Parent':'3','Member': '7','Code': '124','Subject': 'Org H','value': 0.3},
{'ID':'17','Parent':'3','Member': '8','Code': '124','Subject': 'Org H','value': 0.25},
{'ID':'18','Parent':'3','Member': '9','Code': '123','Subject': 'Org I','value': 0.45},
{'ID':'19','Parent':'3','Member': '10','Code': '123','Subject': 'Org J','value': 0.8},
{'ID':'20','Parent':'3','Member': '10','Code': '211','Subject': 'Org I','value': 0.3},
{'ID':'21','Parent':'4','Member': '11','Code': '221','Subject': 'Org K','value': 0.3},
{'ID':'22','Parent':'4','Member': '11','Code': '234','Subject': 'Org K','value': 0.25},
{'ID':'23','Parent':'4','Member': '12','Code': '234','Subject': 'Org K','value': 0.45},
{'ID':'24','Parent':'4','Member': '12','Code': '123','Subject': 'Org L','value': 0.8},
{'ID':'25','Parent':'4','Member': '13','Code': '211','Subject': 'Org M','value': 0.3}
];
来自其他线程的解决方案按 1 组列分组:
// Group by 1 column //
const summed = arr.reduce((acc, cur) => {
const item = acc.length > 0 && acc.find(({
Code
}) => Code === cur.Code)
if (item) {
item.value += cur.value
} else acc.push({Code:cur.Code,value:cur.value});
return acc
}, [])
console.log(arr); // not modified
console.log(summed)
或按所有常用值
// Group by multiple columns //
const res = Array.from(arr.reduce((acc, {value, ...r}) => {
const key = JSON.stringify(r);
const current = acc.get(key) || {...r, value: 0};
return acc.set(key, {...current, value: current.value + value});
}, new Map).values());
console.log(res);
我正在尝试按父级和代码分组以对值求和。
只需在 find()
回调中测试这两个属性,并在推入 acc
时将它们添加到新对象中。
const arr = [
{'ID':'1','Parent':'1','Member': '1','Code': '123','Subject': 'Org A','value': 0.3},
{'ID':'2','Parent':'1','Member': '1','Code': '124','Subject': 'Org A','value': 0.25},
{'ID':'3','Parent':'1','Member': '1','Code': '123','Subject': 'Org B','value': 0.45},
{'ID':'4','Parent':'1','Member': '2','Code': '125','Subject': 'Org A','value': 0.8},
{'ID':'5','Parent':'1','Member': '2','Code': '211','Subject': 'Org C','value': 0.3},
{'ID':'6','Parent':'1','Member': '3','Code': '221','Subject': 'Org B','value': 0.3},
{'ID':'7','Parent':'1','Member': '3','Code': '221','Subject': 'Org C','value': 0.25},
{'ID':'8','Parent':'1','Member': '3','Code': '234','Subject': 'Org A','value': 0.45},
{'ID':'9','Parent':'1','Member': '4','Code': '123','Subject': 'Org A','value': 0.8},
{'ID':'10','Parent':'2','Member': '5','Code': '123','Subject': 'Org D','value': 0.3},
{'ID':'11','Parent':'2','Member': '5','Code': '123','Subject': 'Org E','value': 0.3},
{'ID':'12','Parent':'2','Member': '6','Code': '125','Subject': 'Org E','value': 0.25},
{'ID':'13','Parent':'2','Member': '6','Code': '211','Subject': 'Org F','value': 0.45},
{'ID':'14','Parent':'2','Member': '6','Code': '221','Subject': 'Org F','value': 0.8},
{'ID':'15','Parent':'2','Member': '6','Code': '123','Subject': 'Org G','value': 0.3},
{'ID':'16','Parent':'3','Member': '7','Code': '124','Subject': 'Org H','value': 0.3},
{'ID':'17','Parent':'3','Member': '8','Code': '124','Subject': 'Org H','value': 0.25},
{'ID':'18','Parent':'3','Member': '9','Code': '123','Subject': 'Org I','value': 0.45},
{'ID':'19','Parent':'3','Member': '10','Code': '123','Subject': 'Org J','value': 0.8},
{'ID':'20','Parent':'3','Member': '10','Code': '211','Subject': 'Org I','value': 0.3},
{'ID':'21','Parent':'4','Member': '11','Code': '221','Subject': 'Org K','value': 0.3},
{'ID':'22','Parent':'4','Member': '11','Code': '234','Subject': 'Org K','value': 0.25},
{'ID':'23','Parent':'4','Member': '12','Code': '234','Subject': 'Org K','value': 0.45},
{'ID':'24','Parent':'4','Member': '12','Code': '123','Subject': 'Org L','value': 0.8},
{'ID':'25','Parent':'4','Member': '13','Code': '211','Subject': 'Org M','value': 0.3}
];
const summed = arr.reduce((acc, cur) => {
const item = acc.length > 0 && acc.find(({
Code, Parent
}) => Code === cur.Code && Parent == cur.Parent)
if (item) {
item.value += cur.value
} else acc.push({
Code: cur.Code,
Parent: cur.Parent,
value: cur.value
});
return acc
}, [])
console.log(arr); // not modified
console.log(summed)
根据我上面的评论...
The OP might find an answer in the entirely generic implemented approach posted as a solution to this recently asked question ...
function groupMergeAndAggregateGenerically(collector, item) {
const {
createKey, createMerger, aggregate,
lookup, result = [],
} = collector;
const key = createKey(item);
let merger = lookup.get(key) ?? null;
if (merger === null) {
merger = createMerger(item);
lookup.set(key, merger);
result.push(merger);
}
aggregate(merger, item);
return collector;
}
const arr = [
{ 'ID':'1','Parent':'1','Member': '1','Code': '123','Subject': 'Org A','value': 0.3 },
{ 'ID':'2','Parent':'1','Member': '1','Code': '124','Subject': 'Org A','value': 0.25 },
{ 'ID':'3','Parent':'1','Member': '1','Code': '123','Subject': 'Org B','value': 0.45 },
{ 'ID':'4','Parent':'1','Member': '2','Code': '125','Subject': 'Org A','value': 0.8 },
{ 'ID':'5','Parent':'1','Member': '2','Code': '211','Subject': 'Org C','value': 0.3 },
{ 'ID':'6','Parent':'1','Member': '3','Code': '221','Subject': 'Org B','value': 0.3 },
{ 'ID':'7','Parent':'1','Member': '3','Code': '221','Subject': 'Org C','value': 0.25 },
{ 'ID':'8','Parent':'1','Member': '3','Code': '234','Subject': 'Org A','value': 0.45 },
{ 'ID':'9','Parent':'1','Member': '4','Code': '123','Subject': 'Org A','value': 0.8 },
{ 'ID':'10','Parent':'2','Member': '5','Code': '123','Subject': 'Org D','value': 0.3 },
{ 'ID':'11','Parent':'2','Member': '5','Code': '123','Subject': 'Org E','value': 0.3 },
{ 'ID':'12','Parent':'2','Member': '6','Code': '125','Subject': 'Org E','value': 0.25 },
{ 'ID':'13','Parent':'2','Member': '6','Code': '211','Subject': 'Org F','value': 0.45 },
{ 'ID':'14','Parent':'2','Member': '6','Code': '221','Subject': 'Org F','value': 0.8 },
{ 'ID':'15','Parent':'2','Member': '6','Code': '123','Subject': 'Org G','value': 0.3 },
{ 'ID':'16','Parent':'3','Member': '7','Code': '124','Subject': 'Org H','value': 0.3 },
{ 'ID':'17','Parent':'3','Member': '8','Code': '124','Subject': 'Org H','value': 0.25 },
{ 'ID':'18','Parent':'3','Member': '9','Code': '123','Subject': 'Org I','value': 0.45 },
{ 'ID':'19','Parent':'3','Member': '10','Code': '123','Subject': 'Org J','value': 0.8 },
{ 'ID':'20','Parent':'3','Member': '10','Code': '211','Subject': 'Org I','value': 0.3 },
{ 'ID':'21','Parent':'4','Member': '11','Code': '221','Subject': 'Org K','value': 0.3 },
{ 'ID':'22','Parent':'4','Member': '11','Code': '234','Subject': 'Org K','value': 0.25 },
{ 'ID':'23','Parent':'4','Member': '12','Code': '234','Subject': 'Org K','value': 0.45 },
{ 'ID':'24','Parent':'4','Member': '12','Code': '123','Subject': 'Org L','value': 0.8 },
{ 'ID':'25','Parent':'4','Member': '13','Code': '211','Subject': 'Org M','value': 0.3 },
];
const { result: mergedData } = arr
.reduce(groupMergeAndAggregateGenerically, {
// OP: "I am trying to group by Parent and Code ..."
createKey: ({ Parent, Code }) => [Parent, Code].join('_'),
createMerger: ({ Parent, Code }) => ({ Parent, Code, value: 0 }),
// OP: "[and] ... to sum the value."
aggregate: (merger, { value }) => merger.value += value,
lookup: new Map,
result: [],
});
console.log({ mergedData });
.as-console-wrapper { min-height: 100%!important; top: 0; }