ES6特定方法循环遍历两个数组并在每个数组中查找匹配项?

4
假设我有两个对象数组,我想要比较它们:
var arr1 = [
  {
    name: 'A', type: "Dog"
  },
  {
    name: 'B', type: "Zebra"
  },
  {
    name: 'C', type: "Cat"
  },
  {
    name: 'D', type: "Dingo"
  }
]

var arr2 = [
  {
    name: 'A', type: "Wolf"
  },
  {
    name: 'B', type: "Echidna"
  },
  {
    name: 'C', type: "Wallaby"
  },
  {
    name: 'D', type: "Rabbit"
  }
]

假设arr1是旧数据,arr2是来自API的更新数据。
我想循环遍历数组,找到名称匹配的对象。如果有匹配项,我想将typearr1更新为arr2
代码示例:
for(var i = 0; i<arr1.length; i++){
  for(var x = 0; x<arr2.length; x++){
    if(arr1[i].name === arr2[x].name){
      arr1[i].type = arr2[x].type;
    }
  }
}

我想知道在ECMAScript 6中是否有任何更新的方法可以更轻松地完成这个任务(在实际情况下,逻辑更加复杂,循环内部嵌套循环会感觉非常笨重);

Array.prototype.findfindIndex - zerkms
所有的对象都会有不同的名称吗? - Oriol
@Oriol 是的,name 是一个唯一标识符。有时 arr2 会引入 arr1 中没有的名称,需要插入它们。 - JVG
1
如果名称是唯一标识符,那么你应该将它们用作对象中的键,这样你就可以始终具有恒定时间查找,而不必通过两个数组进行迭代来查找匹配项。 - user5004821
2个回答

5

在ES2015中,您不会使用这种数据结构,而应该使用映射(Map)

var map1 = new Map([
  ['A', "Dog"],
  ['B', "Zebra"],
  ['C', "Cat"],
  ['D', "Dingo"]
]);
var map2 = new Map([
  ['A', "Wolf"],
  ['B', "Echidna"],
  ['C', "Wallaby"],
  ['D', "Rabbit"]
]);

然后,要使用map2的数据更新map1,您需要使用以下代码:
for(let [key, value] of map2)
  map1.set(key, value);

地图操作需要平均次数为亚线性。如果使用哈希实现,它们应该是常量。然后总成本将是线性的。

另外,由于键是字符串,您可以考虑使用普通对象。您可以使用Object.create(null)创建它,以防止继承Object.prototype的属性,并使用Object.assign分配属性。

var obj1 = Object.assign(Object.create(null), {
  A: "Dog",
  B: "Zebra",
  C: "Cat",
  D: "Dingo"
});
var obj2 = Object.assign(Object.create(null), {
  A: "Wolf",
  B: "Echidna",
  C: "Wallaby",
  D: "Rabbit"
});

然后,要使用obj2中的数据更新obj1,您可以使用以下方法:

for(let key in obj2)
  obj1[key] = obj2[key];

很可能对象将使用哈希实现,因此每个赋值平均而言是常数时间。总成本将是线性的。


即使在更复杂的对象数组中?(真实世界的数据有更多的键和值)。这个问题比尝试应用于我的用例更为粗略/通用,但我也对在这里真实世界中起作用的内容感兴趣。 - JVG
2
@Jascination 当然可以。Map 操作需要平均亚线性,因此这是一个好选择。另外,由于键是字符串,旧的 Object.create(null) 也是一个不错的选择。 - Oriol
我认为您需要添加 if (map1.has(key)) / if (key in obj2) 条件以准确地满足 OP 的要求。 - Bergi
1
@Bergi OP 说过 "有时arr2会引入arr1中没有的名称,需要插入", 所以不需要检查。 - Oriol
1
@Oriol:啊,我明白了——这只是他嵌套循环的不同行为。 - Bergi

2
您可以使用forEach循环(ES5)或ES6中的for..of循环:
for (let item1 of arr1) {
  for (let item2 of arr2) {
    if(item1.name === item2.name){
      item1.type = item2.type;
    }
  }
}

如果这些列表非常长,我建议将更新后的列表放入哈希映射中,这样您的时间复杂度就是线性的,而不是二次的。

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