ES2015 +通过对象数组作为值有效地将对象数组转换为分组哈希图的方法

时间:2019-04-22 18:52:26

标签: javascript ecmascript-6

我正在尝试找到一种优雅而有效的方法,将对象数组转换为由键(在本例中为“ groupByThisKey”)索引的对象。我相信它是一个哈希图。

我能够提出一个原始版本

在下面解释了一些数据:

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})));

2 个答案:

答案 0 :(得分:1)

现代方式将使用Map,而不是对象:

const groupedByKey = new Map();
for (const obj of arr) {
  if (!groupedByKey.has(obj.groupByThisKey))
    groupedByKey.set(obj.groupByThisKey, []);
  groupedByKey.get(obj.groupByThisKey).push(obj);
}

答案 1 :(得分:1)

您实现的事情是非常正确的,让我通过使用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;
}, {}));

在这里,您将以最时髦的方式编写它。效果不佳,下面的下一个版本(此后)将具有更好的性能,因为它不是在迭代时新创建对象或数组的。

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;
    }, {}
))