按数组中的对象分组最有效的方法是什么?
例如,给定此对象数组:
[
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
]
我正在表格中显示这些信息。我想通过不同的方法进行分组,但我想对值求和。
我将Undercore.js用于其groupby函数,这很有用,但并不能完成全部任务,因为我不希望它们“拆分”,而是“合并”,更像SQL groupby方法。
我要找的是能够合计特定值(如果需要)。
因此,如果我按阶段分组,我希望收到:
[
{ Phase: "Phase 1", Value: 50 },
{ Phase: "Phase 2", Value: 130 }
]
如果我组了阶段/步骤,我会收到:
[
{ Phase: "Phase 1", Step: "Step 1", Value: 15 },
{ Phase: "Phase 1", Step: "Step 2", Value: 35 },
{ Phase: "Phase 2", Step: "Step 1", Value: 55 },
{ Phase: "Phase 2", Step: "Step 2", Value: 75 }
]
是否有一个有用的脚本,或者我应该坚持使用Undercore.js,然后遍历生成的对象,自己计算总数?
基于@Ceasar Bautista的原始想法,我修改了代码并使用typescript创建了一个groupBy函数。
static groupBy(data: any[], comparator: (v1: any, v2: any) => boolean, onDublicate: (uniqueRow: any, dublicateRow: any) => void) {
return data.reduce(function (reducedRows, currentlyReducedRow) {
let processedRow = reducedRows.find(searchedRow => comparator(searchedRow, currentlyReducedRow));
if (processedRow) {
// currentlyReducedRow is a dublicateRow when processedRow is not null.
onDublicate(processedRow, currentlyReducedRow)
} else {
// currentlyReducedRow is unique and must be pushed in the reducedRows collection.
reducedRows.push(currentlyReducedRow);
}
return reducedRows;
}, []);
};
此函数接受一个回调(比较器)和一个第二个回调(onDuplicate),该回调比较行并查找副本。
用法示例:
data = [
{ name: 'a', value: 10 },
{ name: 'a', value: 11 },
{ name: 'a', value: 12 },
{ name: 'b', value: 20 },
{ name: 'b', value: 1 }
]
private static demoComparator = (v1: any, v2: any) => {
return v1['name'] === v2['name'];
}
private static demoOnDublicate = (uniqueRow, dublicateRow) => {
uniqueRow['value'] += dublicateRow['value'];
};
使命感
groupBy(data, demoComparator, demoOnDublicate)
将执行计算值和的分组。
{name: "a", value: 33}
{name: "b", value: 21}
我们可以根据项目的需要创建任意多个回调函数,并根据需要聚合这些值。在一个例子中,我需要合并两个数组,而不是求和数据。
我已经改进了答案。此函数获取组字段数组并返回分组对象,该对象的键也是组字段的对象。
function(xs, groupFields) {
groupFields = [].concat(groupFields);
return xs.reduce(function(rv, x) {
let groupKey = groupFields.reduce((keyObject, field) => {
keyObject[field] = x[field];
return keyObject;
}, {});
(rv[JSON.stringify(groupKey)] = rv[JSON.stringify(groupKey)] || []).push(x);
return rv;
}, {});
}
let x = [
{
"id":1,
"multimedia":false,
"language":["tr"]
},
{
"id":2,
"multimedia":false,
"language":["fr"]
},
{
"id":3,
"multimedia":true,
"language":["tr"]
},
{
"id":4,
"multimedia":false,
"language":[]
},
{
"id":5,
"multimedia":false,
"language":["tr"]
},
{
"id":6,
"multimedia":false,
"language":["tr"]
},
{
"id":7,
"multimedia":false,
"language":["tr","fr"]
}
]
groupBy(x, ['multimedia','language'])
//{
//{"multimedia":false,"language":["tr"]}: Array(3),
//{"multimedia":false,"language":["fr"]}: Array(1),
//{"multimedia":true,"language":["tr"]}: Array(1),
//{"multimedia":false,"language":[]}: Array(1),
//{"multimedia":false,"language":["tr","fr"]}: Array(1)
//}
具有排序功能
export const groupBy = function groupByArray(xs, key, sortKey) {
return xs.reduce(function(rv, x) {
let v = key instanceof Function ? key(x) : x[key];
let el = rv.find(r => r && r.key === v);
if (el) {
el.values.push(x);
el.values.sort(function(a, b) {
return a[sortKey].toLowerCase().localeCompare(b[sortKey].toLowerCase());
});
} else {
rv.push({ key: v, values: [x] });
}
return rv;
}, []);
};
示例:
var state = [
{
name: "Arkansas",
population: "2.978M",
flag:
"https://upload.wikimedia.org/wikipedia/commons/9/9d/Flag_of_Arkansas.svg",
category: "city"
},{
name: "Crkansas",
population: "2.978M",
flag:
"https://upload.wikimedia.org/wikipedia/commons/9/9d/Flag_of_Arkansas.svg",
category: "city"
},
{
name: "Balifornia",
population: "39.14M",
flag:
"https://upload.wikimedia.org/wikipedia/commons/0/01/Flag_of_California.svg",
category: "city"
},
{
name: "Florida",
population: "20.27M",
flag:
"https://upload.wikimedia.org/wikipedia/commons/f/f7/Flag_of_Florida.svg",
category: "airport"
},
{
name: "Texas",
population: "27.47M",
flag:
"https://upload.wikimedia.org/wikipedia/commons/f/f7/Flag_of_Texas.svg",
category: "landmark"
}
];
console.log(JSON.stringify(groupBy(state,'category','name')));