对对象数组进行分组的最有效方法

新手上路,请多包涵

对数组中的对象进行分组的最有效方法是什么?

例如,给定这个对象数组:

[
    { 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" }
]

我在表格中显示此信息。我想对不同的方法进行分组,但我想对这些值求和。

我将 Underscore.js 用于它的 groupby 函数,这很有帮助,但并不能完全解决问题,因为我不希望它们“拆分”而是“合并”,更像是 SQL group by

我正在寻找的将能够总计特定值(如果需要)。

所以如果我做了 groupby Phase ,我想收到:

[
    { Phase: "Phase 1", Value: 50 },
    { Phase: "Phase 2", Value: 130 }
]

如果我做了 groupy Phase / Step ,我会收到:

[
    { 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 }
]

是否有对此有用的脚本,或者我应该坚持使用 Underscore.js,然后循环遍历生成的对象以自己进行总计?

原文由 D‘Arcy Rail-Ip 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 708
2 个回答

如果你想避免使用外部库,你可以简洁地实现 groupBy() 的 vanilla 版本,如下所示:

 var groupBy = function(xs, key) {
 return xs.reduce(function(rv, x) {
 (rv[x[key]] = rv[x[key]] || []).push(x);
 return rv;
 }, {});
 };

 console.log(groupBy(['one', 'two', 'three'], 'length'));

 // => {3: ["one", "two"], 5: ["three"]}

原文由 Ceasar Bautista 发布,翻译遵循 CC BY-SA 4.0 许可协议

使用 ES6 地图对象:

 /**
 * @description
 * Takes an Array<V>, and a grouping function,
 * and returns a Map of the array grouped by the grouping function.
 *
 * @param list An array of type V.
 * @param keyGetter A Function that takes the the Array type V as an input, and returns a value of type K.
 *                  K is generally intended to be a property key of V.
 *
 * @returns Map of the array grouped by the grouping function.
 */
//export function groupBy<K, V>(list: Array<V>, keyGetter: (input: V) => K): Map<K, Array<V>> {
//    const map = new Map<K, Array<V>>();
function groupBy(list, keyGetter) {
    const map = new Map();
    list.forEach((item) => {
         const key = keyGetter(item);
         const collection = map.get(key);
         if (!collection) {
             map.set(key, [item]);
         } else {
             collection.push(item);
         }
    });
    return map;
}

// example usage

const pets = [
    {type:"Dog", name:"Spot"},
    {type:"Cat", name:"Tiger"},
    {type:"Dog", name:"Rover"},
    {type:"Cat", name:"Leo"}
];

const grouped = groupBy(pets, pet => pet.type);

console.log(grouped.get("Dog")); // -> [{type:"Dog", name:"Spot"}, {type:"Dog", name:"Rover"}]
console.log(grouped.get("Cat")); // -> [{type:"Cat", name:"Tiger"}, {type:"Cat", name:"Leo"}]

const odd = Symbol();
const even = Symbol();
const numbers = [1,2,3,4,5,6,7];

const oddEven = groupBy(numbers, x => (x % 2 === 1 ? odd : even));

console.log(oddEven.get(odd)); // -> [1,3,5,7]
console.log(oddEven.get(even)); // -> [2,4,6]

关于地图: https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

原文由 mortb 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题