检查一组集合中的重复项的更有效方法是啥

Posted

技术标签:

【中文标题】检查一组集合中的重复项的更有效方法是啥【英文标题】:What is a more efficient way to check for duplicates in an array of sets检查一组集合中的重复项的更有效方法是什么 【发布时间】:2021-07-19 07:34:25 【问题描述】:

鉴于此输入:

const set1 = new Set([10, "someText", a: 1, b: 2]);
const set2 = new Set([10, "someText", a: 1, b: 2]);
const set3 = new Set([5, "someText", a: 3, b: 4]);
const arr = [set1, set2, set3];

combineDupSets(arr);

想要的结果:

[
  Set  10, 'someText',  a: 1, b: 2  ,
  Set  5, 'someText',  a: 3, b: 4  
]

我正在编写一个函数来消除所有重复的集合,并且由于 Set() 在它是一个对象或集合本身时不会检查重复,所以我写了以下内容:

function combineDupSets(arr) 
  const hold = [];

  arr.forEach(set =>
    const copySet = [...set];
    const stringify = JSON.stringify(copySet);
    if(hold.indexOf(stringify) === -1) 
      hold.push(stringify)
    
  )


  const end = hold.map(item => JSON.parse(item));

  const res = end.map(item => item = new Set(item))

  return res;

在这里,我必须使用 3 个大小为 O(n) 的数组来检查这一点,我只是想知道是否有任何其他可读的解决方案可以更有效地检查时间和空间复杂度?

谢谢

【问题讨论】:

两个集合何时相等?如果它们包含相同的元素?广告订单重要吗? 请添加想要的结果。 我想了解您为什么需要这种数据结构。 添加了想要的结果!广告顺序无关紧要 【参考方案1】:

不要在数组中使用indexOf,而是考虑将集合放在对象或映射上,其中键是字符串化集合,值是原始集合。假设这些值是有序的:

function combineDupSets(arr) 
   const uniques = new Map();
   for (const set of arr) 
      uniques.set(JSON.stringify([...set]), set);
   
   return [...uniques.values()];

这个

迭代arr (O(n)) 对其中的每个项目进行一次迭代(总共O(n * m) - 无法绕过) 遍历创建的 Map 并将其放入数组 (O(n))

如果设置的值不一定按顺序排列 - 例如,如果您有

Set([true, 'foo'])
Set(['foo', true])

这应该被认为是相等的,那么它会变得更加复杂,因为每个 Set 中的每个项目不仅必须被迭代,而且还要与 每个其他 Set 中的每个其他项目进行比较 不知何故。实现这一点的一种方法是按字符串化值排序:

function combineDupSets(arr) 
   const uniques = new Map();
   for (const set of arr) 
      const key = [...set].map(JSON.stringify).sort().join();
      uniques.set(key, set);
   
   return [...uniques.values()];

【讨论】:

一次不错!你可以返回unique.values() 还是必须使用扩展运算符? .values 返回一个迭代器,所以如果你想要一个数组作为结果,你必须将迭代器展开成一个数组。 知道了。所以另一个问题:如果我使用indexOf,时间复杂度将是O(n),但是如果我使用map,因为我添加了O(n*m)时间,为什么这样更有效?还是因为我们只创建另一个数组和一个映射而不是 3 个数组,所以效率更高,但它们会简化为 O(n) 吗? JSON.stringify(copySet) - 或JSON.stringify([...set]) - 是O(m),其中m 是集合中的项目数。但是您的hold.indexOf(stringify) 方法是another O(n),其中n 是集合数。相比之下,uniques.set 的 Map 方法是 O(1) 操作。【参考方案2】:

您可以迭代集合并检查值并仅在它们共享相同的对象引用时才将对象视为相等。

function combineDupSets(array) 
    return array.reduce((r, s) => 
        const values = [...s];
        if (!r.some(t => s.size === t.size && values.every(Set.prototype.has, t))) r.push(s);
        return r;
    , []);


const
    a =  a: 1, b: 2 ,
    b =  a: 3, b: 4 ,
    set1 = new Set([10, "someText", a]),
    set2 = new Set([10, "someText", a]),
    set3 = new Set([5, "someText", b]),
    arr = [set1, set2, set3];

console.log(combineDupSets(arr).map(s => [...s]));

【讨论】:

以上是关于检查一组集合中的重复项的更有效方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

识别和删除数组中重复项的最有效方法是啥?

通过聚合在pandas组中查找频繁项的最有效方法是啥[重复]

去除list集合中重复项的几种方法

如何找到具有重复项的集合的所有子集? [关闭]

复杂类型集合去掉重复项的实现方法

检测段和连接器集合中所有闭合路径的最有效方法是啥?