按数组中的对象分组最有效的方法是什么?
例如,给定此对象数组:
[
{ 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,然后遍历生成的对象,自己计算总数?
具有排序功能
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')));
我会检查声明性js groupBy,它似乎正符合您的要求。它也是:
非常有性能(性能基准)用打字机书写,所以所有打字都包括在内。不强制使用第三方类似数组的对象。
import { Reducers } from 'declarative-js';
import groupBy = Reducers.groupBy;
import Map = Reducers.Map;
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" },
{ 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" }
];
data.reduce(groupBy(element=> element.Step), Map());
data.reduce(groupBy('Step'), Map());
使用ES6的简单解决方案:
该方法有一个返回模型,可以比较n个财产。
const compareKey = (item, key, compareItem) => {
return item[key] === compareItem[key]
}
const handleCountingRelatedItems = (listItems, modelCallback, compareKeyCallback) => {
return listItems.reduce((previousValue, currentValue) => {
if (Array.isArray(previousValue)) {
const foundIndex = previousValue.findIndex(item => compareKeyCallback(item, currentValue))
if (foundIndex > -1) {
const count = previousValue[foundIndex].count + 1
previousValue[foundIndex] = modelCallback(currentValue, count)
return previousValue
}
return [...previousValue, modelCallback(currentValue, 1)]
}
if (compareKeyCallback(previousValue, currentValue)) {
return [modelCallback(currentValue, 2)]
}
return [modelCallback(previousValue, 1), modelCallback(currentValue, 1)]
})
}
const itemList = [
{ type: 'production', human_readable: 'Production' },
{ type: 'test', human_readable: 'Testing' },
{ type: 'production', human_readable: 'Production' }
]
const model = (currentParam, count) => ({
label: currentParam.human_readable,
type: currentParam.type,
count
})
const compareParameter = (item, compareValue) => {
const isTypeEqual = compareKey(item, 'type', compareValue)
return isTypeEqual
}
const result = handleCountingRelatedItems(itemList, model, compareParameter)
console.log('Result: \n', result)
/** Result:
[
{ label: 'Production', type: 'production', count: 2 },
{ label: 'Testing', type: 'testing', count: 1 }
]
*/