JavaScript比较多个对象数组

5

如何比较多个对象数组,并添加新属性以记录每个对象出现的次数和所在数组的索引?比较对象时需要使用 name 属性。

例子:

var arrays = [
  [
    {
      name: 'aa',
      value: 1
    },
    {
      name: 'ab',
      value: 2
    },
    {
      name: 'ac',
      value: 3
    },
    {
      name: 'aa',
      value: 1
    }
  ],
  [
    {
      name: 'aa',
      value: 1
    },
    {
      name: 'ab',
      value: 2
    },
  ],
  [
    {
      name: 'ac',
      value: 3
    },
    {
      name: 'aa',
      value: 1
    }
  ]
]

执行后,来自上述数组的对象应具有以下属性:
[
  [
    {
      name: 'aa',
      value: 1,
      occurrences: 3,
      where: [0, 1, 2]
    },
    {
      name: 'ab',
      value: 2,
      occurrences: 2,
      where: [0, 1]
    },
    {
      name: 'ac',
      value: 3,
      occurrences: 2,
      where: [0, 2]
    },
    {
      name: 'aa',
      value: 1,
      occurrences: 3,
      where: [0, 1, 2]
    }
  ],
  [
    {
      name: 'aa',
      value: 1,
      occurrences: 3,
      where: [0, 1, 2]
    },
    {
      name: 'ab',
      value: 2,
      occurrences: 2,
      where: [0, 1]
    }
  ],
  [
    {
      name: 'ac',
      value: 3,
      occurrences: 2,
      where: [0, 2]
    },
    {
      name: 'aa',
      value: 1,
      occurrences: 3,
      where: [0, 1, 2]
    }
  ]
]

基本上,我想检查是否存在具有特定name属性的对象在其他数组中存在。

这是我想到的解决方案: 1. 循环遍历具有最多对象的数组
2. 循环遍历每个对象
3. 循环遍历其他数组并应用Array.prototype.find()
但是这将花费很多时间,因为我的每个数组都至少有500个对象...


1
直接使用循环嵌套的解决方案可以工作。虽然可能不是最有效的,但如果您没有太多的对象,那么这样做就可以了。 - dfsq
我想要在循环中嵌套循环,但每个数组都将至少有500个对象。 - Valip
2个回答

1
这看起来像是简单的reduce,直到我注意到嵌套数组)所以更像是展平+reduce,并带有内存。
下面的代码正在执行所需的操作,只是属性名称很短(因为我在手机上输入):
let f = (ai, a,v,i,m) => {
    if (!a[v.id]) {
    a[v.id] = {id: v.id, v: v.name, count: 1, at: [ai]};
    } else {
    a[v.id].count += 1;
    a[v.id].at.push(ai);
    }
    return a;
};
let r = [[{id: 'aa', value: 42}], [{id: 'ba', value: 11}, {id: 'aa', value: 42}]]
.reduce ((a, v, i) => v.reduce (f.bind (null, i),a), {}); 
console.log (r);

代码仅访问数组中的每个元素一次,因此复杂度为O(n),在最多拥有一百万个元素的数组上运行不应该有问题(例如1000个包含1000个元素的数组或200个包含5000个元素的数组)。

我该如何修改代码以不计算数组中的重复项?我只想查看对象是否存在于数组中,并仅计算一次,即使包含该名称的多个对象的数组中找到它。 - Valip
哪个计数器?出现次数计数器还是主机数组计数器? - c69
主机数组计数器...这意味着如果一个数组有3个对象的出现,它只应该被计算一次。我只需要知道该对象是否存在于该数组中。 - Valip

1
你可以使用array#reduce来获取对象中元素的出现次数和索引。然后,你可以使用Object.assign()修改arrays中的对象,只需添加whereoccurrences属性即可。

var arrays = [ [ { name: 'aa', value: 1 }, { name: 'ab', value: 2 }, { name: 'ac', value: 3 }, { name: 'aa', value: 1 } ], [ { name: 'aa', value: 1 }, { name: 'ab', value: 2 }, ], [ { name: 'ac', value: 3 }, { name: 'aa', value: 1 } ] ];

var result = arrays.reduce((res, arr, index) => {
  arr.forEach(({name,value}) => {
    res[name] =  res[name] || {occurrences: 0};
    res[name]['where'] = res[name]['where'] || [];
    if(!res[name]['where'].includes(index)){
      res[name]['where'].push(index);
      res[name].occurrences += 1;
    }
  });
  return res;
},{});

arrays.forEach(arr => arr.forEach(obj => Object.assign(obj, result[obj.name])));
console.log(arrays);


这个代码很好用,但是我该如何修改它以不计算数组中的重复项?我只想知道一个对象是否存在于数组中,并且只计算一次,即使包含该名称的多个对象的数组中找到了它。 - Valip
我已经更新了代码,不再从数组中计算重复项。if(!res[name]['where'].includes(index)){这行代码检查是否有重复项。 - Hassan Imam

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