按数组中的对象分组最有效的方法是什么?
例如,给定此对象数组:
[
{ 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,然后遍历生成的对象,自己计算总数?
这是一个基于TS的功能,不是性能最好的,但很容易阅读和理解!
function groupBy<T>(array: T[], key: string): Record<string, T[]> {
const groupedObject = {}
for (const item of array) {
const value = item[key]
if (groupedObject[value] === undefined) {
groupedObject[value] = []
}
groupedObject[value].push(item)
}
return groupedObject
}
我们以->
const data = [
{ 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" },
];
console.log(groupBy(data, 'Step'))
{
'Step 1': [
{
Phase: 'Phase 1',
Step: 'Step 1',
Task: 'Task 1',
Value: '5'
},
{
Phase: 'Phase 1',
Step: 'Step 1',
Task: 'Task 2',
Value: '10'
}
],
'Step 2': [
{
Phase: 'Phase 1',
Step: 'Step 2',
Task: 'Task 1',
Value: '15'
},
{
Phase: 'Phase 1',
Step: 'Step 2',
Task: 'Task 2',
Value: '20'
}
]
}
我从underscore.js fiddler那里借用了这个方法
window.helpers=(function (){
var lookupIterator = function(value) {
if (value == null){
return function(value) {
return value;
};
}
if (typeof value === 'function'){
return value;
}
return function(obj) {
return obj[value];
};
},
each = function(obj, iterator, context) {
var breaker = {};
if (obj == null) return obj;
if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (var i = 0, length = obj.length; i < length; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
var keys = []
for (var key in obj) if (Object.prototype.hasOwnProperty.call(obj, key)) keys.push(key)
for (var i = 0, length = keys.length; i < length; i++) {
if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
}
}
return obj;
},
// An internal function used for aggregate "group by" operations.
group = function(behavior) {
return function(obj, iterator, context) {
var result = {};
iterator = lookupIterator(iterator);
each(obj, function(value, index) {
var key = iterator.call(context, value, index, obj);
behavior(result, key, value);
});
return result;
};
};
return {
groupBy : group(function(result, key, value) {
Object.prototype.hasOwnProperty.call(result, key) ? result[key].push(value) : result[key] = [value];
})
};
})();
var arr=[{a:1,b:2},{a:1,b:3},{a:1,b:1},{a:1,b:2},{a:1,b:3}];
console.dir(helpers.groupBy(arr,"b"));
console.dir(helpers.groupBy(arr,function (el){
return el.b>2;
}));
如果您需要通过以下方式进行多组:
const populate = (entireObj, keys, item) => {
let keysClone = [...keys],
currentKey = keysClone.shift();
if (keysClone.length > 0) {
entireObj[item[currentKey]] = entireObj[item[currentKey]] || {}
populate(entireObj[item[currentKey]], keysClone, item);
} else {
(entireObj[item[currentKey]] = entireObj[item[currentKey]] || []).push(item);
}
}
export const groupBy = (list, key) => {
return list.reduce(function (rv, x) {
if (typeof key === 'string') (rv[x[key]] = rv[x[key]] || []).push(x);
if (typeof key === 'object' && key.length) populate(rv, key, x);
return rv;
}, {});
}
const myPets = [
{name: 'yaya', type: 'cat', color: 'gray'},
{name: 'bingbang', type: 'cat', color: 'sliver'},
{name: 'junior-bingbang', type: 'cat', color: 'sliver'},
{name: 'jindou', type: 'cat', color: 'golden'},
{name: 'dahuzi', type: 'dog', color: 'brown'},
];
// run
groupBy(myPets, ['type', 'color']));
// you will get object like:
const afterGroupBy = {
"cat": {
"gray": [
{
"name": "yaya",
"type": "cat",
"color": "gray"
}
],
"sliver": [
{
"name": "bingbang",
"type": "cat",
"color": "sliver"
},
{
"name": "junior-bingbang",
"type": "cat",
"color": "sliver"
}
],
"golden": [
{
"name": "jindou",
"type": "cat",
"color": "golden"
}
]
},
"dog": {
"brown": [
{
"name": "dahuzi",
"type": "dog",
"color": "brown"
}
]
}
};