【问题标题】:Efficient and accurate way to compact and compare Python lists?压缩和比较 Python 列表的有效且准确的方法?
【发布时间】:2026-02-14 13:35:01
【问题描述】:

我正在尝试在两个 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 列表的方法的任何想法,以便可以将它们与其他列表的简单相等性进行比较? IE。一个真正有效的散列系统? 加分:为什么上面的方法不起作用?

编辑:

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

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

我也已经在做诸如字符串剥离之类的事情,以使数据更加统一,但似乎无济于事。我不是在寻找一个非常聪明的差异逻辑,即00.0 相同。

编辑 2:

问题解决了。基本上起作用的是我需要更多的预格式化,比如转换整数和浮点数,等等 AND 我需要更改我的散列函数。这两个变化似乎都对我有用。

【问题讨论】:

  • 你能说更多关于它是如何不起作用的吗?
  • 你为什么不用一套?为什么是列表?
  • @Ned 基本上,如果两个文件中的两个相同,我的代码没有为它们获得相同的哈希值。我不知道为什么,在 CSV 到字符串的方法中,或者在读者如何以不同的方式读取文件时,它可能会失败很多步骤。 @S.Lott 我实际上使用的是哈希行对字典,但我想让示例代码更简单。

标签: python list comparison hash


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 仅读取文件假定没有两行数据相同但表示方式不同,即具有不同的引用、转义、间距等。
    • @intuited 如果您立即在读取结果上调用str(),您是否仍然遇到同样的问题?
    • 通过 csv.reader() 对其进行规范化;查看问题编辑。例如>>> cr = csv.reader(['1,"2",3', '1,2,3']); str(cr.next()) == str(cr.next())True
    【解决方案3】:

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

    我可以想象上述内容无法按书面说明工作的唯一原因是因为您的散列函数并不总是为给定输入提供相同的输出。您可以测试第二次运行 old.csv 是否生成相同的列表。它可能与错误的空格、制表符而不是空格、不同的大小写、“自动

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

    在填充 hashes 变量后,您应该考虑将其转换为一个集合 (hashes = set(hashes)),以便您的查找比线性查找更快。

    【讨论】:

    • +1 用于使用集合。这也可以防止多次存储相同的哈希,从而节省内存。
    • 哎呀,其实我看错了。从一开始就将hashes做成一个集合不是更好吗?他说记忆很重要,而不是处理时间。
    • 所有这些都是正确的,但需要存储{hashval: [row1, row2, ... rowN]},以便可以检查冲突情况,其最终效果是形成一组隐含的哈希值作为字典的键。 rowN 最好存储为 file_offsetN 以避免无数次遍历文件。
    • @msw 我现在实际上正在试用 hash:row 字典。
    • 是的,dict 方法(哈希:set_of_rows)似乎是最有效的方法。我的回答背后的想法通常是提供与 OP 所展示的功能类似的功能,但中间段落解决了 OP 实现中没有的可能考虑因素。由于内存是一个问题,将所有输入数据存储在内存中并不是自动可行的,但至少需要将哈希值映射到可用于查找的信息行。
    【解决方案4】:

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

    0, 0
    0, 0.0
    

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

    【讨论】:

      【解决方案5】:

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

      我们无法告诉您“为什么上述方法不起作用”,因为您还没有告诉我们“惨遭失败”和“不起作用”的症状是什么。

      【讨论】:

        【解决方案6】:

        我很确定“失败得很惨”这一行指的是由于您当前的算法为 O(N^2) 而导致的时间失败,这对于您的文件有多大是非常不利的。如前所述,您可以使用set 来缓解此问题(将变为 O(N)),或者如果您由于某种原因无法做到这一点,那么您可以对哈希列表进行排序并使用二进制搜索在它上面(将变为 O(N log N) 这也是可行的。如果你走二进制搜索路线,你可以使用bisect 模块。

        另外,有人提到您可能会遇到哈希冲突的问题:当行不完全相同时,两行会产生相同的哈希。如果您发现这是您遇到的问题,您将必须在每个哈希中存储有关在何处查找与old.csv 文件中的哈希对应的行的信息,然后查找该行并比较这两行。

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

        【讨论】:

          【解决方案7】:

          您是否考虑过运行排序(如果可能) - 当然您必须重复两次 - 但可能会解决内存问题。

          【讨论】:

            最近更新 更多