查找要消除重复的项目

finding items to de-duplicate

本文关键字:项目 查找      更新时间:2023-10-16

我有一个数据池(X1..XN),我想为其查找相等值的组。比较是非常昂贵的,而且我不能把所有的数据都保存在内存中。

例如,我需要的结果是:

X1等于X3和X6
X2是唯一的
X4等于X5

(行的顺序或行内的顺序无关紧要)。

如何通过成对比较实现这一点


到目前为止,我拥有的是:

将所有对(Xi,Xk)与i<k、 利用传递性:如果我已经找到了X1=X3和X<sub+1>==X6,我就不需要比较X3与X2

所以我可以使用以下数据结构:

  map: index --> group
  multimap: group --> indices

其中组是任意分配的(例如输出中的"行号")。

对于具有i<k:

  • 如果i和k都已经分配了一个组,则跳过

  • 如果比较相等:

    • 如果我已经分配了一个组,那么把k放在该组中
    • 否则,为i创建一个新组,并将k放入其中
  • 如果它们不相等:

    • 如果我还没有分配组,请为我分配一个新组
    • k相同

如果我仔细处理项目的顺序,应该有效,但我想知道这是否是解决这个问题的最佳/最不令人惊讶的方法,因为这个问题似乎有点常见。


背景/更多信息:目的是消除项目的重复存储。它们已经有了一个散列,在发生冲突的情况下,我们希望保证进行完整的比较。所讨论的数据的大小具有非常尖锐的长尾分布。

迭代算法(找到任意两个重复项,共享它们,重复直到没有重复项为止)可能更容易,但我们希望不修改诊断。代码库是C++,与STL/boost容器或算法配合使用会很好。

[edit]关于哈希:为了这个问题,请假设一个无法替换的弱哈希函数。

这是对现有数据进行一次性重复数据消除所必需的,并且需要处理哈希冲突。最初的选择是"快速哈希,并在碰撞时进行比较",选择的哈希有点弱,但更改它会破坏向后兼容性。即便如此,我还是用一句简单的话睡得更好:如果发生碰撞,你不会得到错误的数据而不是写关于狼袭击的博客。

这里有另一个可能更简单的数据结构,用于利用传递性。制作一个需要进行的比较队列。例如,如果有4个项目,则为[(1,2)、(1,3)、[(1,4)、](2,3)、/(2,4)、.(3,4)]。还有一个数组,用于您已经完成的比较。在每次比较之前,请检查该比较以前是否进行过,每次找到匹配项时,请遍历队列并将匹配项索引替换为其较低的索引。

例如,假设我们弹出(1,2),进行比较,它们不相等,将(1,2-)推到already_visited的数组中并继续。接下来,弹出(1,3),发现它们是相等的。此时,遍历队列并将所有3个替换为1个。队列将是[(1,4),(2,1),(2,4),[(1,4],依此类推。当我们到达(2,1。

但我同意前面的回答。由于比较在计算上很昂贵,您可能希望首先计算一个快速、可靠的哈希表,然后再将此方法应用于冲突。

所以。。。你已经有哈希了?这个怎么样:

  • 哈希排序和分组
  • 将尺寸为1的所有组打印为唯一
  • 比较碰撞

比较冲突的提示:为什么不用不同的算法重新处理它们呢?冲洗,重复。

(此外,我假设两种不同的哈希算法不会在不同的数据上发生冲突,但这可能是安全的假设…)

对每个项目进行哈希。列出pair<hash,item_index>。您可以通过按哈希对该列表进行排序或将其放入std::multimap来查找组。

输出组列表时,需要比较哈希冲突的项。因此,对于每个项目,您将进行一次哈希计算和大约一次比较。以及哈希列表的排序。

我同意使用第二个(希望是改进的)散列函数的想法,这样你就可以解决一些弱散列的冲突,而不需要进行昂贵的成对比较。既然你说你有内存限制问题,希望你能把整个哈希表(带辅助密钥)放在内存中,对于表中的每个条目,你都会为磁盘上对应于该密钥对的记录存储一个记录索引列表。然后问题是,对于每个密钥对,是否可以将所有记录加载到具有该密钥对的内存中。如果是这样的话,那么您就可以对密钥对进行迭代;对于每个密钥对,释放前一个密钥对的内存中的任何记录,并将当前密钥对的记录加载到内存中,然后像您已经概述的那样在这些记录之间进行比较。如果你有一个密钥对,你不能将所有记录都放入内存,那么你必须加载部分子集,但你绝对应该能够在内存中维护你为密钥对找到的所有组(每个组都有一个唯一的记录代表),因为如果你有好的二次哈希,唯一记录的数量就会很小。