javascript - ES2015+ 有效地将对象数组转换为以对象数组作为值的分组 HashMap 的方法

标签 javascript ecmascript-6

我正在尝试找到一种优雅且有效的方法来将对象数组转换为由键索引的对象(在本例中为“groupByThisKey”)。我相信它被称为 HashMap 。

我能够想出一个原始版本

用下面的一些数据进行解释:

const arr = [
  {
    id: 1,
    name: "one",
    groupByThisKey: 'groupA'
  },
  {
    id: 2,
    name: "two",
    groupByThisKey: 'groupB'
  },
  {
    id: 3,
    name: "three",
    groupByThisKey: 'groupB'
  },
  {
    id: 4,
    name: "four",
    groupByThisKey: 'groupA'
  }
];

const groupedByKey = {};

arr.map(obj => {
  if (groupedByKey[obj.groupByThisKey])
    groupedByKey[obj.groupByThisKey].push(obj)
  else
    groupedByKey[obj.groupByThisKey] = [obj]
});

console.log(groupedByKey)

它确实给出了所需的输出:

{
  groupA: [
   {
     id: 1,
     name: "one",
     groupByThisKey: 'groupA'
   },
   {
     id: 4,
     name: "four",
     groupByThisKey: 'groupA'
   }
  ],
  groupB: [
   {
     id: 2,
     name: "two",
     groupByThisKey: 'groupB'
   },
   {
     id: 3,
     name: "three",
     groupByThisKey: 'groupB'
   }
  ]
}

但以一种相当原始的方式。我更愿意使用更短、更现代的方法来执行此操作,如果可能的话,可能使用 object.assign 或 reduce,但无法理解它,因为我需要每个键都有一个值数组。

我找到了许多示例,这些示例似乎都适用于每个键只有一个值的用例,但就我而言,我需要一个按该键分组的对象数组,所以我找到的例子只会采用最新的。这是一个例子:

const hash = Object.assign({}, ...array.map(s => ({[s.key]: s.value})));

最佳答案

你实现的东西非常正确,让我使用 reducer 消除副作用:

const arr = [
  {
    id: 1,
    name: "one",
    groupByThisKey: 'groupA'
  },
  {
    id: 2,
    name: "two",
    groupByThisKey: 'groupB'
  },
  {
    id: 3,
    name: "three",
    groupByThisKey: 'groupB'
  },
  {
    id: 4,
    name: "four",
    groupByThisKey: 'groupA'
  }
];

console.log(arr.reduce((groupedByKey,obj) => {
  if (groupedByKey[obj.groupByThisKey])
    groupedByKey[obj.groupByThisKey].push(obj)
  else
    groupedByKey[obj.groupByThisKey] = [obj]
    
  return groupedByKey;
}, {}));

这里你可以用最 fp 的方式来写它。并不是真正的性能,下面的下一个版本(在此之后)将具有更好的性能,因为它不是在每次迭代中创建对象或数组。

const arr = [
    {
        id: 1,
        name: "one",
        groupByThisKey: 'groupA'
    },
    {
        id: 2,
        name: "two",
        groupByThisKey: 'groupB'
    },
    {
        id: 3,
        name: "three",
        groupByThisKey: 'groupB'
    },
    {
        id: 4,
        name: "four",
        groupByThisKey: 'groupA'
    }
];

console.log(arr.reduce(
    (groups, x) => 
        ({ 
            ...groups, 
            [x.groupByThisKey]: [
                ...(groups[x.groupByThisKey] || []),
                x
            ]
        })
    , {}
))

与上面具有相同逻辑的更简单版本:

const arr = [
    {
        id: 1,
        name: "one",
        groupByThisKey: 'groupA'
    },
    {
        id: 2,
        name: "two",
        groupByThisKey: 'groupB'
    },
    {
        id: 3,
        name: "three",
        groupByThisKey: 'groupB'
    },
    {
        id: 4,
        name: "four",
        groupByThisKey: 'groupA'
    }
];

console.log(arr.reduce(
    (groups, x) => {
        let key = x.groupByThisKey;
        
        if (groups[key] === undefined)
            groups[key] = [];
            
        groups[key].push(x);
        
        return groups;
    }, {}
))

关于javascript - ES2015+ 有效地将对象数组转换为以对象数组作为值的分组 HashMap 的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55799551/

相关文章:

javascript - 从 html 调用函数并从 angularjs 获取结果

javascript - Fullpage.js:如何自动添加下一个或上一个部分的名称

javascript - 修改交互不起作用

javascript - `Class<Component>`在JS中的含义

javascript - 为什么以下函数在执行 `greet({ name = ' Rauno' } = {} )` instead of ` greet(name = 'Rauno')`?

javascript - 带有选项卡的 Twitter Bootstrap Modal 默认为第一个选项卡

javascript - 没有等号的 Angular div 标签属性

reactjs - ES6 类中对 super(props) 的调用重要吗?

javascript - 如何在 ES2015 中克隆一个对象(包括其原型(prototype))

javascript - 如何通过按开始按钮使时钟滴答作响