【问题标题】:Compare lines of 2 input files, and output third file with differences比较 2 个输入文件的行,并输出有差异的第三个文件
【发布时间】:2015-02-02 15:36:20
【问题描述】:

我有一个函数允许我输入两个文件文本文件,比较这些文本文件,最后创建第三个文件的差异。它适用于文件中的每一行,并且要使其正常工作,文件 1 和文件 2 中的整行文本必须相似才能注册。这是我的问题,我希望仅根据冒号后面的第一个单词将行与相似的行进行比较 - 冒号后面的文本不需要相同。

文件的结构是这样的;

文件 1 示例:

A:dog 
B:cat 
C:bird 
D:cow 
E:pig

文件 2 示例:

B:sheep
D:duck

我希望新创建的文件(文件 3)的输出具有以下内容:

A:dog
C:bird
E:pig

我希望该函数仅根据分号前的第一个字符串(字母)输出文件 1 中不在文件 2 中的条目。这目前仅在文件 2 中的整行文本与文件 1 相同时才有效:

def comparison(F1,F2,F3):
   with open(F1, 'r') as f:
      d=set(f.readlines())
   with open(F2, 'r') as f:
      e=set(f.readlines())
   open(F3, 'a').close()
   with open(F3, 'a') as f:
      for line in list(d-e):
         f.write(line)

comparison('file1.txt','file2.txt','file3.txt')

我主要尝试使用line.split(':')[0]来抓取冒号前的第一个字符串进行比较,但没有成功。

【问题讨论】:

  • 好的...所以你想输出一个行列表,其中冒号之前的文本对于其中一个文件是唯一的?
  • 是的:)。如果冒号之前的文本不在文件 2 中,我希望它从文件 1 输入到文件 3 中

标签: python file function compare output


【解决方案1】:

这是一个快速解释器会话,用于显示使用 defaultdict 的进程。填写文件I/O就交给你了。

>>> from collections import defaultdict
>>> list1 = ['a: xyz', 'b:123']
>>> list2 = ['a: dupe', 'c:456']
>>> d = defaultdict(list)
>>> for item in list1 + list2:
...     k,v = item.split(':')
...     d[k].append(v)
... 
>>> d
defaultdict(<type 'list'>, {'a': [' xyz', ' dupe'], 'c': ['456'], 'b': ['123']})
>>> ['{}:{}'.format(k,d[k][0]) for k in d if len(d[k]) == 1]
['c:456', 'b:123']

更新:文件 i/o 的示例,应请求提供。

from collection import defaultdict
list1 = open('file1.txt', 'r').readlines()
list2 = open('file2.txt', 'r').readlines()
d = defaultdict(list)
for item in list1 + list2:
    k,v = item.split(':')
    d[k].append(v)
with open('file3.txt', 'a') as output:
    output.writelines(['{}:{}\n'.format(k,d[k][0]) for k in d if len(d[k]) == 1])

用英文解压最后一行,意思是:

  • 遍历 d(我们的 dict)中的键
  • 忽略我们为该键添加了多个项目的项目 (非唯一键)
  • 对于我们没有忽略的每个项目(是唯一的),格式化密钥并 值返回到 'k:v' 字符串并添加换行符
  • 对于重新组装的字符串(加上换行符)的集合,编写 整个事情都在我们的文件中。

【讨论】:

  • 哇,这超出了我的范围 :) - 有没有更简单的方法可以使用我在问题中提供的代码来做到这一点?
  • @Eric1989 哈...这利用了一些 Python 习语,乍一看有点紧凑,但值得努力学习。 FMI:docs.python.org/2/library/collections.htmldocs.python.org/2/tutorial/…
  • 我会花时间学习这个阅读这个;但是现在,是否有一种更“初学者”的方法可以使用与我在问题中的代码类似的结构来实现这一点?这主要是为了学习目的,目前这对我来说差距太大了。 :D - 非常感谢您的帮助。
  • 你这样做的方式不起作用,因为你想根据元素的 one 特征比较两组,而不是元素本身相同。我保证将这个“匹配”特征用作键的字典是处理这种情况的最有效方法,因为您只需要遍历每个集合一次。如果您不使用 dict,您可能最终会通过 len(list1) 次数对 list2 进行迭代,反之亦然。
  • 好的,谢谢。您是否可以通过使用两个输入文件并将结果输出到第三个文件来编辑您的答案?我会非常感激,因为我目前正在努力理解你的,并希望在尝试掌握它之前看到它的工作。谢谢。
【解决方案2】:

嗯,有很多方法可以实现您的目标。事实上,你已经很接近了。使用集合来处理值的想法是评估每个文件中两个列表之间差异的好方法。但是,您需要将冒号之前的值与冒号之后的值分开,否则您将比较整行,这在您的情况下是错误的。得到差异后,您需要根据差异检索两个文件中的整行,以将它们写入新文件。

因此,解决方案的一个想法是:当您读取一个文件时,将每一行保存在字典中以使其将来可检索,并将冒号之前的值保存在一个集合中(每个文件)来评估值的差异(就像你已经做过的那样)。

实际上它的意思是:

d = {}  # Our dictionary to store the lines
a = set()  # a set for the first file
b = set()  # a set for the second file

with open('file1') as fp:
    for line in fp:
        key, value = line.split(':')  # this separate the values in each line
        d[key] = value.strip()  # add one line to the dictionary
        a.add(key)  # save just the value from the colon left

然后,您需要与第二个文件相同。也许您会将其作为一个函数来使您的代码更出色且更易于维护。

在此之后,您将拥有一本完整的字典。既然你不想写重复的值,我们的代码覆盖一些值是可以的。

现在,您需要评估差异。你这样做的方式很好。但是,如果您知道第一个文件比第二个文件具有更多的值并且可能还有其他问题,那么它就可以工作。您需要查看 set 方法以正确实现此目的(提示:联合和交集),但让我们按照您的方式进行:

diff = a - b

最后,让我们根据我们的差异编写从字典中检索它们的结果:

with open('results', 'w') as fp:
    for key in diff:  # you can use sorted(diff) instead just diff here
        fp.write("{0}:{1}\n".format(key, d[key]))

当然,这种方式不是更pythonic的方式,但它是某种简单的方式。其他答案可能比这个简单。

【讨论】:

    【解决方案3】:

    使用时应将文件置于 CSV 格式。因此,只需将它们放入 excel 并保存为 CSV。

    执行此操作后。

    f = open('file1.csv')
    csv_f = csv.reader(f)
    animals1 = []
    
    for row in csv_f:
        animals1.append(row[0])   #[] put number in there. 0 = first Column 
    f.close()
    
    f = open('file2.csv')
    csv_f = csv.reader(f)
    animals2 = []
    
    for row in csv_f:
        animals2.append(row[0])      
    f.close()
    
    
    animals1 = set(animals1)
    animals2 = set(animals2)
    
    print animals1.difference(aniamls2)
    

    所以这段代码基本上会读取您的 csv 文件,并打印出差异。 你可以实现它并将其写入一个新文件。

    【讨论】:

    • 你知道的文本文件有类似的方法吗?
    • 你必须在文本文件中这样做吗?
    • 这是出于学习目的,所以我希望能够在文本文件中完成,哈哈。我现在只是卡住了 - 我在问题中的代码是我能做的最好的,但它只比较整行文本,而不是冒号前的字符串。
    【解决方案4】:

    编辑:警告,根据此答案的 cmets:此方法不是解决此问题的最佳方法。但它似乎确实回答了用户根据他的进一步评论提出的问题......

    OP 要求采用一种“更简单”的方式来实现这一点,而无需使用字典。这可以通过读入每个文件的所有行然后只获取每行的第一个字母来完成。然后根据file2中的字母数组过滤数据。这将非常依赖于文本文件的特定格式,以及 file1 被 file2 过滤的事实,反之亦然。但是,也就是说,执行此操作的 python 应该是这样的(行号来自我的文本编辑器,而不是代码的一部分):

    1 f=open("./file1.txt","r")
    2 data1=f.readlines()
    3 letter1=[]
    4 f.close()
    5 
    6 g=open("./file2.txt","r")
    7 data2=g.readlines()
    8 letter2=[]
    9 g.close()
    10 
    11 #just take the first character (the 'A', 'B', etc)
    12 for dat in data1:
    13     letter1.append(dat[0]) 
    14 for dat in data2:
    15     letter2.append(dat[0])
    16 
    17 h=open("output.txt","w")
    18 for dat in data1:
    19     if dat[0] not in letter2:
    20         h.write(dat)
    21 
    22 h.close()
    

    【讨论】:

    • 您好 - 感谢您的回答。我刚刚对此进行了测试,它成功了一半。文件 1 (A:dog) 的第一行没有显示在输出文件中?
    • @hft 同意这是 OP 所要求的。但是,这不是一个好的答案,因为如果 file1 和/或 file2 很大,您的工作量会急剧增加。即使出于学习目的(也许尤其是出于学习目的),我也确实会避免以这种方式比较集合。您正在迭代 letter2 len(data1) 的所有项目的次数。
    • @Eric1989,这对我来说似乎工作正常。不知道为什么第一行没有显示给你......也许在第一行的开头还有其他字符(如空格)。
    • @dylrei,是的,你是对的。我只是想我会给那个人他要求的东西。它适用于他的小示例文件,如果他需要为大量输入执行此操作,他很快就会发现它不能很好地工作......
    猜你喜欢
    • 2018-01-09
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多