如何在es6中将对象合并并返回新数组

10

假设有两个物体。

const a = [
  { id: '1-1-1', name: 'a111' },
  { id: '1-1-2', name: 'a112' },
  { id: '1-2-1', name: 'a121' },
  { id: '1-2-2', name: 'a122' },
  { id: '2-1-1', name: 'a211' },
  { id: '2-1-2', name: 'a212' }
]
const b = ['1-1', '1-2', '2-1']

并且结果

  {

      '1-1':[
        { id: '1-1-1', name: 'a111' },
        { id: '1-1-2', name: 'a112' },
      ],
      '1-2':[
          { id: '1-2-1', name: 'a121' },
          { id: '1-2-2', name: 'a122' },
      ],
      '2-1':[
        { id: '2-1-1', name: 'a211' },
        { id: '2-1-2', name: 'a212' },
      ]
    }

基本上,我想对数据进行分组。

我使用includes来检查从b的项目是否与a的id匹配。然后构建新的数组。

这是我的尝试(fiddle):

return b.map(item => a.map(jtem => {
  if(jtem.id.includes(item)){
    return {
      [item]: jtem
    }
  }
}))

不知何故,它无法工作。

另外,是否有巧妙的方法可以避免嵌套的 for 循环或 map 函数?


结果不应该是一个对象吗? - Jack Bashford
@JackBashford 嘿,伙计,抱歉,你是对的,我刚刚更新了它。 - SPG
你真的需要使用 includes 吗?我建议使用 startsWith - Bergi
@Bergi 谢谢,我认为 startWith 更好。 - SPG
1个回答

13

您可以按照以下步骤进行操作:

  • 在数组 b 上应用 reduce()

  • 在每次迭代中,对数组 a 运用 filter()

  • 使用String.prototype.startsWith()获取所有以 b 中的项开头的 a 中的项
  • 最后将其设置为 ac 的属性并返回 ac

const a = [
  { id: '1-1-1', name: 'a111' },
  { id: '1-1-2', name: 'a112' },
  { id: '1-2-1', name: 'a121' },
  { id: '1-2-2', name: 'a122' },
  { id: '2-1-1', name: 'a211' },
  { id: '2-1-2', name: 'a212' }
]
const b = ['1-1', '1-2', '2-1']

let res = b.reduce((ac,b) => {
  
  ac[b] = a.filter(x => x.id.startsWith(b));
  return ac;

},{})
console.log(res)

根据评论区@Falco的建议,扫描一遍大型的a会更好,于是这里提供了这个版本。实际上,这个版本在性能方面表现更好。

const a = [
  { id: '1-1-1', name: 'a111' },
  { id: '1-1-2', name: 'a112' },
  { id: '1-2-1', name: 'a121' },
  { id: '1-2-2', name: 'a122' },
  { id: '2-1-1', name: 'a211' },
  { id: '2-1-2', name: 'a212' }
]
const b = ['1-1', '1-2', '2-1']


let res = a.reduce((ac,x) => {
  let temp = b.find(y => x.id.startsWith(y))
  if(!ac[temp]) ac[temp] = [];
  ac[temp].push(x);
  return ac;
},{})

console.log(res)

注意: startsWith 不受 IE 支持。所以你可以使用 indexOf 来创建 polyfill。

if(!String.prototype.startWith){
  String.prototype.startsWith = function(str){
    return this.indexOf(str) === 0
  }
}


1
虽然问题中明确指出了要使用es6,并且IE不支持es6功能,但我想提一下,startsWith()在IE中无法运行(而reduce,filter和设置对象属性完全没有问题,如果IE > 9),如果有人想要与startsWith相同的功能,他们可以使用一些substring来实现自己的功能。 :) - Neyt
对于大数组 a 和小数组 b,我可能会选择使用 a.reduce(...),因为它具有局部性,并且只需要扫描一次大数组。 - Falco
@MaheerAli 谢谢 - 这里有一个比较两者的基准测试 :-) https://jsbench.me/dfjtoadysr/1 - Falco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接