我有一个包含约2000万行(~1.5GB)的文件。每一行的形式如下:
entry_1 entry_2 entry_3 ......... entry_5
该文件包含重复项,但格式为:
entry_2 entry_1 entry_3 ......... entry_5
某些行的内容相同,但前两个元素通常(可能始终)切换。
有没有人对如何从这样大小的文件中删除此类重复项有任何建议?
感谢。
答案 0 :(得分:5)
合适的解决方案取决于您拥有的约束以及运行此操作的频率。
如果这是一次性(或不经常)操作,并且如果内存使用不是一个大问题,那么这样就足够了:
visited = set() # use set for faster lookups
with open(out_filename, "w") as outfile:
with open(in_filename, "r") as infile:
for line in infile:
x = line.split()
k = (tuple(sorted(x[:2])), tuple(x[2:]))
if k not in visited:
outfile.write(line)
visited.add(k)
内存使用情况取决于我们需要在visited
中跟踪的唯一条目的数量。如果没有多少重复项,您最终将得到内存中的几乎所有数据。
如果内存使用成为问题,您可以分多个阶段执行此操作:
第2步& 3可以合并,因为在执行排序时比较条目时可以简单地丢弃重复项。
如果您不介意使用shell,可以使用sort -u yourfile
完成第2步和第3步。
请注意,这会更改文件中行的顺序(您提到的不是问题)。
以显着降低内存使用率为代价,您可以使用基于文件的数据库来存储和查找访问过的条目(代替set()
)。
您可以通过在内存中存储条目的哈希来加快速度,并且只在哈希匹配时查询数据库以确认条目是否确实相同。哈希可以像获取每个条目的第一个字符,或使用内置hash()
函数一样简单,也可以选择existing hash algorithm。每种方法都是性能,散列大小和冲突频率之间的折衷。一个好的选择取决于您的数据和约束。
这需要一些努力才能找到最佳解决方案。如果您需要经常执行此操作,则值得着手。
答案 1 :(得分:1)
separator = " "
aSet = set()
with open('myfile', 'rU') as infile:
for line in infile:
tempLine = line.split(separator)
tempLine = tempLine[1:2] + tempLine[0:1] + tempLine[2:]
tempLine = separator.join(tempLine)
if line not in aSet and tempLine not in aSet:
aSet.add(line)
现在,aSet
包含唯一的行列表,无论是否已交换entry_1
和entry_2
。
编辑:如果可以交换所有条目并且该行仍被视为唯一,那么:
separator = " "
aSet = set()
with open('myfile', 'rU') as infile:
for line in infile:
aSet.add(frozenset(line.split(separator)))