【问题标题】:What algorithm to use to delete duplicates?使用什么算法删除重复项?
【发布时间】:2011-11-03 13:27:46
【问题描述】:

假设我们有一些文件,例如“A.txt”。我们知道有一些重复的元素。 “A.txt”非常很大,比内存大十倍以上,大概 50GB 左右。有时,B 的大小大约等于 A 的大小,有时它会比 A 的大小小 很多倍。 让它有这样的结构:

a 1
b 2
c 445
a 1

我们需要获取文件“B.txt”,它不会有这样的重复。例如,应该是这样的:

a 1
b 2
c 445

我想到了复制A并执行B的算法,然后在B中获取第一个字符串,然后相互查找,如果找到相同的,则删除重复项。然后取第二个字符串等。

但我认为它方式太慢了。我可以使用什么?

A 是不是数据库!请不要使用 SQL。

对不起,没说,排序就OK了。

虽然可以排序,但是如果不能排序呢?

【问题讨论】:

  • 我认为 CouchDB 是一个 NoSQL 解决方案。
  • 你说'A.txt'不适合内存。您知道 A 的唯一元素(即 B 中的结果)是否适合内存?我认为他们不会,但如果他们这样做,就会大大简化问题。
  • B 也不适合内存。
  • 您有 Microsoft Access 吗?即使使用您的 txt 文件,这也可以在 Access 中轻松完成。
  • 我需要算法,而不是实现。

标签: algorithm duplicates


【解决方案1】:

一种解决方案是对文件进行排序,然后一次将一行复制到一个新文件中,过滤掉连续的重复项。

那么问题就变成了:如何对一个太大而无法放入内存的文件进行排序?

这里是how Unix sort does it

另见this question

【讨论】:

  • 但是,文件不是原来的顺序。但是,没有-1,因为这可能还不错。 OP应该告诉。
  • 你可以用行号装饰文件,按照你想去重复的键进行排序,去重复,然后重新排序(和去除)行号。跨度>
【解决方案2】:

假设您可以将文件的1/k'th 放入内存中,并且仍有空间用于工作数据结构。整个文件可以在k 或更少的通道中处理,如下所示,这可能比根据行长和排序算法常量对整个文件进行排序要快得多。排序平均值O(n ln n) 和下面的过程是O(k n) 最坏的情况。例如,如果行平均 10 个字符并且有 n = 5G 行,ln(n) ~ 22.3。另外,如果你的输出文件B比输入文件A小很多,这个过程可能只需要一到两次。

流程:

  1. 为输入缓冲区 I 分配几兆字节,为结果缓冲区 R 分配几千兆字节,为哈希表 H 分配大约千兆字节。打开输入文件 F 和输出文件 O。
  2. 重复:从 F 中填充 I,然后通过步骤 3 将其处理为 R。
  3. 对于 I 中的每一行 L,检查 L 是否已经在 H 和 R 中。如果是,继续下一个 L,否则将 L 添加到 R 并将其哈希添加到 H。
  4. 当 R 已满时,假设有 M 个条目,将其写入 O。然后重复从 F 填充 I,按照步骤 3 进行去重,然后写入 O。在 EOF(F) 处转到 5。
  5. 重复(使用旧 O 作为输入 F,新 O 作为输出):从 F 读取 M 行并复制到 O。然后按照步骤 2 和 3 加载 R 和 H,并使用 dedup 复制到 EOF(F)和以前一样。将 M 设置为每个 O 文件开头的新的非重复行数。

请注意,在每次传递之后,O 的前 M 行不包含重复项,并且这些 M 行在 O 的其余部分中都没有重复。因此,每次传递至少处理原始文件的 1/k'th ,因此处理最多需要k 次。

更新 1 应该使用单独的输出文件 P,而不是在已处理的前导行中重复写出和读回,在每个传递结束时将处理缓冲区 R 附加到该文件.当结果文件 B 几乎与 A 一样大时,这将读取和写入量减少了 k/2,或者当 B 远小于 A 时,减少了一点;但在任何情况下都不会增加 I/O 的数量。

【讨论】:

  • 我喜欢你的算法 :) 你是数学家吗?这是第一个不那么明显的答案:D
  • 程序员/分析师多于数学家。随意投票给我的答案! :)
【解决方案3】:

您基本上必须建立一个可搜索的结果集(如果该语言让您想起数据库技术,这绝非偶然,无论您多么讨厌数据库处理与您相同的问题这一事实)。

其中一种可能的有效数据结构是排序范围(可实现为某种树)或哈希表。因此,当您处理文件时,您可以有效地将每条记录插入结果集中,并且在该阶段您可以检查结果是否已经存在。完成后,您将拥有一组减少的唯一记录。

除了复制实际记录之外,您的结果集还可以存储对任何原始记录的某种引用。这取决于记录是否足够大以使其成为更有效的解决方案。

或者您可以简单地在原始数据上添加一个标记,无论该记录是否包含。

(还可以考虑对二进制数据使用像 NetCDF 这样的高效存储格式,因为文本表示的访问和处理速度要慢得多。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    • 2019-07-15
    • 2019-07-27
    • 1970-01-01
    • 2013-05-11
    相关资源
    最近更新 更多