【问题标题】:comparing two files and writing the missing values to a file比较两个文件并将缺失值写入文件
【发布时间】:2012-01-09 08:04:15
【问题描述】:

当我尝试比较两个大文件时遇到问题。我想做的是从一个文件中取一行,搜索另一个文件的所有行以查找匹配项,如果没有,则将该行写入另一个文件。我可以通过下面的简单示例重新创建问题:

file1.txt(内容

apple
banana
pear
peach
lime

file_old.txt(内容)

lime
apple
pear
peach

由于我正在寻找 file1 中不在 file_old 中的行,因此我希望 'banana' 将是输出文件中显示的唯一值。但在输出文件“*fill_diff*”中,我显示的是:

apple
banana
banana

我的代码尝试在文件中产生差异有什么问题?

def main():

    file_old = open(r'C:\Users\test\Desktop\file_old.txt', 'r+')
    file_new = open(r'C:\Users\test\Desktop\file1.txt', 'r+')
    file_diff = open(r'C:\Users\test\Desktop\file_diff.txt', 'w')

    for each_line in file_new: 
        for every_line in file_old:
            if each_line == every_line:
                break
            file_diff.write(each_line)

    file_old.close()
    file_new.close()
    file_diff.close()

main()

谢谢!

【问题讨论】:

    标签: python file loops compare


    【解决方案1】:

    您需要在循环的每次迭代开始时回到file_old 的开头。像这样的:

    for each_line in file_new:
        file_old.seek(0)
        for every_line in file_old:
            ...
    

    此外,您最内层循环的逻辑似乎是错误的。我想你想要类似的东西

    for each_line in file_new:
        file_old.seek(0)
        found = False
        for every_line in file_old:
            if each_line == every_line:
                found = True
                break
    
        if not found:
            file_diff.write(each_line)
    

    【讨论】:

    • 我无法让它工作。如果我在示例中添加 file_old.seek(0) ,那么我得到的输出比我预期的还要多。会不会是break语句的位置?
    • 我编辑了我的答案,更正了您最内层循环的逻辑。再次检查我的答案以获得完整的独家新闻。
    • 非常感谢您的帮助!
    【解决方案2】:

    FWIW,difflib module 专为此类用例而设计。

    如果需要手动操作,Python的sets可以让你更轻松:

    file_diff = open(r'C:\Users\test\Desktop\file_diff.txt', 'w')
    oldlines = set(open(r'C:\Users\test\Desktop\file_old.txt', 'r'))
    for line in open(r'C:\Users\test\Desktop\file1.txt', 'r'):
        if line not in oldlines:
            file_diff.write(line)
    

    【讨论】:

      【解决方案3】:

      srgerg 的回答会起作用。

      但是,多次读取文件将具有非常大的运行时复杂性。因此,如果文件(虽然很大)小到足以放入内存,那么您可以考虑将file_old 中的所有行放入数据结构中进行比较:

      old_lines = set((line.strip() for line in open(r'C:\Users\test\Desktop\file_old.txt', 'r+')))
      file_new = open(r'C:\Users\test\Desktop\file1.txt', 'r+')
      file_diff = open(r'C:\Users\test\Desktop\file_diff.txt', 'w')
      
      for line in file_new:
          if line.strip() not in old_lines:
              file_diff.write(line)
      file_new.close()
      file_diff.close()
      

      希望对你有帮助

      【讨论】:

      • 谢谢。这实际上有点酷。您在 python 文档或在线中是否有任何地方可以解释您在第 1 行中使用的数据结构的更多信息?
      • 当然。这叫一套。它就像一个列表,但它具有 O(1) 查找时间,因为它是通过散列实现的。你可以阅读更多关于它here
      • 集合是一个取自数学的概念,它在很多地方都非常有用。 en.wikipedia.org/wiki/Set_(abstract_data_type)一旦明白了,很多事情就变得很简单了。
      • inspectorG4dget 有旧链接.. 新链接:sets
      • 感谢 John Doe 的更新。我不知道我的链接有误
      【解决方案4】:

      我怀疑你想以任何顺序丢失行

      这是一个基于set()的快速而肮脏的实现:

      def readfile(name):
          afile = open(name, 'r+')
          lines = set([l.strip() for l in afile])
          afile.close()
          return lines
      
      def main():
          oldset = readfile(r'file_old.txt')
          newset = readfile(r'file1.txt')
      
          file_diff = open(r'file_diff.txt', 'w')
      
          for diff in (newset - oldset):
              file_diff.write(diff)
      
          file_diff.close()
      
      main()
      

      对于非常大的输入文件,这可能无法很好地扩展。

      【讨论】:

        【解决方案5】:

        您可以在 O(n + n*log(n)) 中执行此操作,方法是先对两个文件进行排序,然后同时对两个文件进行迭代。

        # sort file1 and file2 on disk or in memory
        while len(file1) > 0 and len(file2) > 0:
            while file1[0] < file2[0]:
                diff.append(file1[0])
                file1 = file1[1:]
            while file1[0] > file2[0]:
                diff.append(file2[0])
                file2 = file2[1:]
            while file1[0] == file2[0]:
                file1 = file1[1:]
                file2 = file2[1:]
        diff = diff + file1 + file2 # add the rest to the diff
        

        【讨论】:

        • 这将具有比 O(n*log(n)) 高得多的运行时间 - 更像是 O(n^3)。这是由于第一个while循环的O(n)和每个内部while循环的O(n^2)(由列表拼接的线性时间复杂度引起)
        • 这只是为了使代码简洁易读。通常你会遍历文件对象,但这在我脑海中很快就完成了。
        • 我的 cmets 不是针对您代码的可读性,而是针对您对其运行时的分析。此外,迭代文件对象会导致 O(n^2) 算法,这仍然非常低效
        • 请再看一遍,忽略数组切片复杂度时,此代码排序 + O(n)
        • 是的。忽略列表拼接,你有排序 (O(nlog(n))) + O(n)。 O(nlog(n)) 占主导地位,所以你的运行时间是 O(n*log(n))
        【解决方案6】:

        如果您不能假设文件已排序,那么我会这样做

        def diffUnsorted(fn1, fn2) :
            return set([l.strip() for l in open(fn1) if l.strip() != ""]) - \
                   set([l.strip() for l in open(fn2) if l.strip() != ""])
        

        不过,如果您要处理大文件,我会采用一种首先对文件进行排序的解决方案,这样您可以获得 O(n) 时间和 O(1) 空间(不计算排序.. )。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-05-01
          • 2014-06-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多