压缩和比较Python列表的高效准确方法?

时间:2010-06-08 01:00:05

标签: python list comparison hash

我正在尝试在两个CSV文件中的各个行之间进行一些复杂的差异。我需要确保一个文件中的一行不会出现在另一个文件中,但我在任一文件中都给出不保证行的顺序。作为一个起点,我一直在尝试比较行的字符串表示的哈希值(即Python列表)。例如:

import csv

hashes = []
for row in csv.reader(open('old.csv','rb')):
  hashes.append( hash(str(row)) )

for row in csv.reader(open('new.csv','rb')):
  if hash(str(row)) not in hashes:
    print 'Not found'

但这是悲惨的失败。我受限于人为强加的内存限制,我无法改变,因此我使用哈希而不是直接存储和比较列表。我正在比较的一些文件的大小可能是数百兆字节。有关准确压缩Python列表的方法的任何想法,以便可以将它们与简单的相等性与其他列表进行比较吗?即一个真正有效的哈希系统? 奖励积分:为什么上述方法无效?

修改

感谢所有伟大的建议!让我澄清一些事情。 “悲惨的失败”意味着在被CSV.reader对象读入之后具有完全相同数据的两行在调用列表对象上的str之后不会散列到相同的值。我将在下面的一些建议中尝试hashlib。我也不能对原始文件进行哈希处理,因为下面的两行包含相同的数据,但行上的字符不同:

1, 2.3, David S, Monday
1, 2.3, "David S", Monday

我也在做像字符串剥离这样的事情,以使数据更加统一,但似乎无济于事。我不是在寻找一种非常智能的差异逻辑,即00.0相同。

编辑2:

问题解决了。基本上工作的是我需要更多的预格式化,如转换int和浮点数,等等 AND 我需要更改我的散列函数。这些变化似乎都适合我。

7 个答案:

答案 0 :(得分:4)

如果不了解更多关于约束的信息,很难给出一个很好的答案,但是如果你可以为每个文件的每一行存储一个哈希值,那么你应该没问题。至少你需要能够存储一个文件的哈希列表,然后你可以将其排序并写入磁盘,然后你可以一起浏览这两个排序列表。

我可以想象上面没有写入的唯一原因是因为你的散列函数并不总是为给定的输入提供相同的输出。您可以测试通过old.csv的第二次运行生成相同的列表。它可能与错误的空格,标签 - 代替空格,不同的大写,“自动

有关

介意,即使哈希值相等,你也不知道线条匹配;你只知道他们可能会匹配。您仍然需要检查候选线是否匹配。 (您可能还会遇到输入文件中多行生成相同哈希的情况,因此您也需要处理它。)

填写hashes变量后,您应该考虑将其转换为集合(hashes = set(hashes)),以便查找速度快于线性。

答案 1 :(得分:2)

鉴于CSV的语法定义松散,两个行在语义上可能是相等的,而在词汇上是不同的。各种Dialect definitions给出了一些线索,即两行如何单独构造良好但不可通约。这个例子展示了他们如何使用相同的方言,而不是字符串等价物:

0, 0
0, 0.0

更多信息有助于更好地回答您的问题。

答案 2 :(得分:1)

需要更多关于“悲惨失败”的含义的信息。如果你没有在两者之间得到正确的比较,也许Hashlib可能会解决这个问题。

我之前在使用内置哈希库时遇到了麻烦,并用它解决了它。

编辑:正如有人在另一篇文章中建议的那样,问题可能在于假设要求两个文件的每一行完全相同。在计算哈希值之前,您可能希望尝试解析csv字段并将它们附加到具有相同格式的字符串(可能是修剪空格,强制小写等)。

答案 3 :(得分:1)

我很确定“失败的悲惨”行是指你当前算法的时间失败是O(N ^ 2),这对于你的文件有多大是非常糟糕的。如前所述,您可以使用set来解决此问题(将成为O(N)),或者如果由于某种原因无法执行此操作,则可以对哈希列表进行排序并使用二进制搜索(将成为O(N log N)也是可行的。如果你进入二进制搜索路径,你可以使用bisect模块。

另外,有人提到你可能会遇到哈希冲突的问题:当行不完全相同时,两行会产生相同的哈希值。如果您发现这是您遇到的问题,则必须存储每个散列的信息,以获取与old.csv文件中的散列相对应的行的位置,然后查找行并比较两者线。

当前方法的一个替代方法是事先对两个文件进行排序(使用某种合并排序到磁盘或shell排序),并保持指向每个文件中的行,比较两行。检查它们是否匹配,如果不匹配则推进测得较小的线。只要O(N log N)方法用于排序,该算法也是O(N log N)。也可以通过将每个文件放入数据库并让数据库对它们进行排序来完成排序。

答案 4 :(得分:0)

这可能是使用hash(错误)的问题。见this SO question;正如答案所指出的那样,你可能想要hashlib

答案 5 :(得分:0)

你需要说出你的问题究竟是什么。您的描述“我需要确保一个文件中的一行不会出现在另一个文件中”与第二个循环的正文if hash(...) in hashes: print "Found (an interloper)"一致,而不是您所拥有的。

我们不能告诉你“为什么上述方法不起作用”,因为你没有告诉我们“悲惨地失败”和“没有工作”的症状是什么。

答案 6 :(得分:0)

您是否考虑过运行某种类型(如果可能的话) - 当然,您必须经历两次 - 但可能会解决内存问题。