从文件中提取与另一个文件中的条件匹配的某些行
Extracting certain rows from a file that match a condition from another file
所以首先,我知道有一些类似问题的答案,但是...我的问题与速度和内存效率有关。
我有一个 60 GB 的文本文件,其中包含 17 个字段和 460,368,082 条记录。第 3 列是个人的 ID,同一个人可以在此文件中有多个记录。让我们调用这个文件,File A
.
我有第二个文件 File B
,它有 1,000,000 个人的 ID,我想提取 File A
中 ID 在 File B
中的行。
我有一台 windows PC,我愿意用 C 或 Python 或任何更快的方式来做这件事……但不确定如何快速有效地做到这一点。
到目前为止,根据我的计算,我提出的每一个解决方案都需要 1.5 年以上的时间。
视情况而定,如果它未排序,您将不得不搜索整个内容,我会为此使用多个线程。如果您将不得不多次执行此搜索,我也会创建一个索引。
如果您有大量内存,您可以创建一个散列 table 来保存字符串。然后,您可以将第一个文件中的所有字符串加载到散列 table 中。然后,一次加载第二个文件中的每个字符串。对于每个字符串,检查它是否在散列 table 中。如果是这样,请报告匹配项。这种方法使用 O(m) 内存(其中 m 是第一个文件中的字符串数)并且至少需要 Ω(m + n) 时间,可能更多,具体取决于散列函数的工作方式。这也是(几乎可以肯定)最简单直接的解决问题的方法。
如果您只有很少的 ram 可以使用,但是有大量的磁盘 space:https://en.wikipedia.org/wiki/External_sorting,您可以将它用到 O(n log n) 时间。
听起来你想做的是先阅读 File B
,收集 ID。您可以将 ID 存储在 set
或 dict
.
中
然后阅读File A
。对于 File A
中的每一行,提取 ID,然后通过检查 set
或 dict
中的成员资格来查看它是否在 File B
中。如果没有,则跳过该行并继续下一行。如果是,则根据需要处理该行。
您正在寻找的是排序合并连接。这个想法是在您要加入的列(ID)上对文件 A 进行排序。在您要加入的列 (ID) 上对文件 B 进行排序。然后使用合并算法读取这两个文件,忽略两者都不匹配的文件。
排序文件可能需要创建中间文件。
如果数据在带有分隔符的文本文件中,您还可以使用 linux 排序命令行实用程序来执行排序。
sort -k3,3 -t'|' fileA > fileA.sorted
sort fileB > fileB.sorted
dos2unix fileB.sorted #make sure the line endings are same style
dos2unix fileA.sorted #make sure the line endings are same style
如果 dos2unix 不可用,这可能用作替代
sort -k3,3 -t'|' fileA | tr -d '\r' > fileA.sorted
sort fileB | tr -d '\r' > fileB.sorted
加入文件
join -1 3 -2 1 -t'|' fileA.sorted fileB.sorted
另一种选择是,如果您有足够的 RAM,则以 HashMap 类型的结构将文件 B 加载到内存中。然后读取文件 A,并在 HashMap 中查找匹配项。我认为任何一种语言都可以正常工作,只是取决于您更喜欢哪种语言。
所以首先,我知道有一些类似问题的答案,但是...我的问题与速度和内存效率有关。
我有一个 60 GB 的文本文件,其中包含 17 个字段和 460,368,082 条记录。第 3 列是个人的 ID,同一个人可以在此文件中有多个记录。让我们调用这个文件,File A
.
我有第二个文件 File B
,它有 1,000,000 个人的 ID,我想提取 File A
中 ID 在 File B
中的行。
我有一台 windows PC,我愿意用 C 或 Python 或任何更快的方式来做这件事……但不确定如何快速有效地做到这一点。
到目前为止,根据我的计算,我提出的每一个解决方案都需要 1.5 年以上的时间。
视情况而定,如果它未排序,您将不得不搜索整个内容,我会为此使用多个线程。如果您将不得不多次执行此搜索,我也会创建一个索引。
如果您有大量内存,您可以创建一个散列 table 来保存字符串。然后,您可以将第一个文件中的所有字符串加载到散列 table 中。然后,一次加载第二个文件中的每个字符串。对于每个字符串,检查它是否在散列 table 中。如果是这样,请报告匹配项。这种方法使用 O(m) 内存(其中 m 是第一个文件中的字符串数)并且至少需要 Ω(m + n) 时间,可能更多,具体取决于散列函数的工作方式。这也是(几乎可以肯定)最简单直接的解决问题的方法。
如果您只有很少的 ram 可以使用,但是有大量的磁盘 space:https://en.wikipedia.org/wiki/External_sorting,您可以将它用到 O(n log n) 时间。
听起来你想做的是先阅读 File B
,收集 ID。您可以将 ID 存储在 set
或 dict
.
然后阅读File A
。对于 File A
中的每一行,提取 ID,然后通过检查 set
或 dict
中的成员资格来查看它是否在 File B
中。如果没有,则跳过该行并继续下一行。如果是,则根据需要处理该行。
您正在寻找的是排序合并连接。这个想法是在您要加入的列(ID)上对文件 A 进行排序。在您要加入的列 (ID) 上对文件 B 进行排序。然后使用合并算法读取这两个文件,忽略两者都不匹配的文件。
排序文件可能需要创建中间文件。
如果数据在带有分隔符的文本文件中,您还可以使用 linux 排序命令行实用程序来执行排序。
sort -k3,3 -t'|' fileA > fileA.sorted
sort fileB > fileB.sorted
dos2unix fileB.sorted #make sure the line endings are same style
dos2unix fileA.sorted #make sure the line endings are same style
如果 dos2unix 不可用,这可能用作替代
sort -k3,3 -t'|' fileA | tr -d '\r' > fileA.sorted
sort fileB | tr -d '\r' > fileB.sorted
加入文件
join -1 3 -2 1 -t'|' fileA.sorted fileB.sorted
另一种选择是,如果您有足够的 RAM,则以 HashMap 类型的结构将文件 B 加载到内存中。然后读取文件 A,并在 HashMap 中查找匹配项。我认为任何一种语言都可以正常工作,只是取决于您更喜欢哪种语言。