【问题标题】:Grouping object entries into object arrays将对象条目分组到对象数组中
【发布时间】:2020-09-16 10:42:31
【问题描述】:

如何根据tag 为组成员创建数组?

标签可以是任何东西,这些只是示例。

示例输入

[
  { tag: 'Red', member: 'Red-Steve' },
  { tag: 'Red', member: 'Red-Adam' },
  { tag: 'Blue', member: 'Blue-John' },
  { tag: 'Blue', member: 'Blue-James' },
  { tag: 'Blue', member: 'Blue-Igor' }
]

示例输出

{
  Red: ['Red-Steve', 'Red-Adam']
  Blue: ['Blue-John', 'Blue-James', 'Blue-Igor']
}

编辑:我刚刚在jsperf 上做了一个测试用例来比较不同答案的效率以及建议的重复问题的答案 https://jsperf.com/group-objects-reduce-vs-for-loop

@Majed Badawi 的 answer 效率最高

【问题讨论】:

标签: javascript arrays typescript javascript-objects


【解决方案1】:

您可以使用简单的set 将它们按tag 分组,如下所示:

let list = [
            { tag: 'Red', member: 'Red-Steve' },
            { tag: 'Red', member: 'Red-Adam' },
            { tag: 'Blue', member: 'Blue-John' },
            { tag: 'Blue', member: 'Blue-James' },
            { tag: 'Blue', member: 'Blue-Igor' }
];
let set = {};
for(let i = 0; i < list.length; i++){
     let current = list[i];
     if(!set[current.tag])
          set[current.tag] = [current.member];
     else
          set[current.tag].push(current.member);
}
console.log(set);

【讨论】:

    【解决方案2】:

    使用标签作为键并附加到数组中收集到对象映射

    d=[
      { tag: 'Red', member: 'Red-Steve' },
      { tag: 'Red', member: 'Red-Adam' },
      { tag: 'Blue', member: 'Blue-John' },
      { tag: 'Blue', member: 'Blue-James' },
      { tag: 'Blue', member: 'Blue-Igor' }
    ]
    console.log(
    d.reduce((acc,{tag,member})=>({...acc, [tag]: [...acc[tag]||[], member]}),{})
    )

    【讨论】:

    • 当然,它正在使用reduce遍历对象数组,使用解构提取tagmember属性,acc是每次迭代后返回的“累积”值,然后它正在合并具有新属性 [tag](将是红色或蓝色)的累积对象映射,然后将成员连接到数组
    • 所有这些答案基本上都在做同样的事情。由于在每次迭代中创建一个对象,我的可能会对非常大的操作产生性能损失。它只是碰巧采取了一种更短的“功能性”方法
    • 这就是我要在这里决定的,因为我最终可能会处理大量对象,您认为for 循环会比reduce 更有效吗?跨度>
    • 我会选择你喜欢的任何东西。如果您的数据结构与您提供的数据结构一样,我认为您实际上不会看到明显的差异。而且,如果您使用 reduce 而不使用 spread 语法来合并对象(例如,您可以使用 Object.assign 代替或像其他答案一样直接分配),您可以避免对象初始化损失。如果你想确定,我会做一个 jsperf 基准测试,尽可能接近你的数据集来检查。
    • 我刚刚对 100 个对象进行了基准测试,for 循环显然是赢家。我用jsben.ch 作记录。
    【解决方案3】:

    以下代码将满足您的要求。它使用 object[variableKey] 语法来获取您要查找的内容。

    const members=[
      { tag: 'Red', member: 'Red-Steve' },
      { tag: 'Red', member: 'Red-Adam' },
      { tag: 'Blue', member: 'Blue-John' },
      { tag: 'Blue', member: 'Blue-James' },
      { tag: 'Blue', member: 'Blue-Igor' }
    ]
    
    //this will be the output object
    const newObj={};
    
    for(memberObj of members){
        const newKey = memberObj.tag;
    
        //if the key already existed, just add the new item to the existing array
        if(newObj[newKey]){newObj[newKey].push(memberObj.member);}
        //if the key didn't exist, create an array value for it with the new object
        else{newObj[newKey]=[memberObj.member];}
    }
    
    console.log(newObj);
    

    【讨论】:

      【解决方案4】:

      我认为这将是用现代语法实现它的好方法。但可能也有一些聚合函数。

      var arr = [
        { tag: 'Red', member: 'Red-Steve' },
        { tag: 'Red', member: 'Red-Adam' },
        { tag: 'Blue', member: 'Blue-John' },
        { tag: 'Blue', member: 'Blue-James' },
        { tag: 'Blue', member: 'Blue-Igor' }
      ];
      
      var newArr = [];
      arr.forEach(o => {
        var existing = newArr[o.tag] && newArr[o.tag].length > 0 ? newArr[o.tag] : [];
        newArr[o.tag] = [...existing, ...[o.member]];
      });
      
      console.log('newArr', newArr);

      在 Chrome 中,它在控制台中给出以下输出

      我们在这里有一个类似的问题Most efficient method to groupby on an array of objects

      【讨论】:

      • 如果您看到一个骗子,您应该投票关闭并将其引用为重复。
      • 嗯。好建议
      • 正如我在我的问题的最新编辑中提到的,我添加了一个指向测试用例的链接,用于测试您链接的问题的接受答案以及此处回答的 2 种方法。您链接的问题的答案比该问题的接受答案慢 20%。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-30
      • 2018-11-25
      • 1970-01-01
      • 1970-01-01
      • 2019-01-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多