从Python中的两个不同文件一次读取两行

时间:2013-01-16 23:33:34

标签: python

我有两个文件,如下所示:

文件1(制表符分隔):

A1   someinfo1     someinfo2    someinfo3
A1   someinfo1     someinfo2    someinfo3
B1   someinfo1     someinfo2    someinfo3
B1   someinfo1     someinfo2    someinfo3

文件2(制表符分隔):

A1   newinfo1     newinfo2    newinfo3
A1   newinfo1     newinfo2    newinfo3
B1   newinfo1     newinfo2    newinfo3
B1   newinfo1     newinfo2    newinfo3

我想从文件1中读取两行(从A1和A1开始的行)和从文件2中读取两行(以A1和A1开头的行)。为了更清楚,我有两个要求:

1) Reading two lines from the same file
2) Read same two lines from the other file.  

准确地说,我想一起阅读四行(两个文件中的两行连续(每个文件两行))。

我在网上搜索并且能够获得一个代码来一起读取两行,但只能从一个文件中读取。

with open(File1) as file1:
        for line1,line2 in itertools.izip_longest(*[file1]*2):

此外,我还能够从两个文件中读取一行:

for i,(line1,line2) in enumerate(itertools.izip(f1,f2)):
        print line1, line2

但我想做某事:

伪代码:

for line1, line2 from file1 and line_1 and line_2 from file2:
              compare line1 with line2
              compare line1 with line_1
              compare line2 with line_1
              compare line2 with line_2

我希望解决方案是一个线性时间的解决方案。所有文件具有相同的行数,并且第一列(主要ID)对于文件中的连续行是相同的,而另一个文件遵循相同的顺序(参见上面的示例)。

感谢。

4 个答案:

答案 0 :(得分:6)

这个怎么样:

with open('a') as A, open('b') as B:
    while True:
        try:
            lineA1, lineA2, lineB1, lineB2 = next(A), next(A), next(B), next(B)
            # compare lines
            # ...
        except StopIteration:
            break

答案 1 :(得分:1)

让我们看看我们如何将这些结合在一起。第一:

with open(File1) as file1:
    for line1,line2 in itertools.izip_longest(*[file1]*2):

好吧,取出for循环,你有一个2行一次的迭代器而不是file,对吗?因此,您可以对file2执行相同的操作。然后你可以zip他们在一起:

with open(File1) as file1, open(File2) as file2:
    f1 = itertools.izip_longest(*[file1]*2)
    f2 = itertools.izip_longest(*[file2]*2)
    for i,((f1_line1, f1_line2), (f2_line1, f2_line2)) in enumerate(itertools.izip(f1,f2)):
        # do stuff

但你真的不想这样做。

首先,大多数人并不直观地阅读izip_longest(*[file1]*2)并意识到它是成对分组的。将其作为一种功能包装起来。事实上,甚至不要自己写这个功能;从itertools documentation开始grouper

现在,它是:

with open(File1) as file1, open(File2) as file2:
    pairs1 = grouper(2, file1)
    pairs2 = grouper(2, file2)
    for i,((f1_line1, f1_line2), (f2_line1, f2_line2)) in enumerate(itertools.izip(f1,f2)):
        # do stuff

接下来,模式匹配可能很酷,但是在复杂表达式中间分解的嵌套模式有点过分。所以,让我们分解它,并通过再次从flatten文档中借用itertools来取消嵌套:

with open(File1) as file1, open(File2) as file2:
    pairs1 = grouper(2, file1)
    pairs2 = grouper(2, file2)
    zipped_pairs = itertools.izip(pairs1, pairs2)
    for i, zipped_pair in enumerate(zipped_pairs):
        f1_line1, f1_line2, f2_line1, f2_line2 = flatten(zipped_pair)
        # do stuff

这个解决方案的优点是它是抽象的和通用的,这意味着如果你以后决定需要5行或3个文件的组,那么这种变化是显而易见的。

这个解决方案的缺点是它是抽象的和通用的,这意味着它不可能像做具体的等价物一样简单。 (例如,如果您没有zip一对grouper,则不必flatten结果。)

答案 2 :(得分:1)

>>> from itertools import izip
>>> with open("file1") as file1, open("file2") as file2:
...     for a1, a2, b1, b2 in izip(file1, file1, file2, file2):
...         print a1, a2, b1, b2
... 
A1   someinfo1     someinfo2    someinfo3
A1   someinfo1     someinfo2    someinfo3
A1   newinfo1     newinfo2    newinfo3
A1   newinfo1     newinfo2    newinfo3

B1   someinfo1     someinfo2    someinfo3
B1   someinfo1     someinfo2    someinfo3
B1   newinfo1     newinfo2    newinfo3
B1   newinfo1     newinfo2    newinfo3

可以将行数设为参数(n),如下所示

for lines in izip(*[file1]*n+[file2]*n):

现在行将是具有n*2元素的元组

答案 3 :(得分:0)

这是一个允许任意数量的具有相同id列的连续行的概括:

from itertools import groupby, izip, product

getid = lambda line: line.partition(" ")[0] # first space-separated column
same_id = lambda lines: groupby(lines, key=getid)

with open(File1) as file1, open(File2) as file2:
     for (id1, lines1), (id2, lines2) in izip(same_id(file1), same_id(file2)):
         if id1 != id2: 
            # handle error here
            break
         # compare all possible combinations
         for a, b in product(lines1, lines2): 
             compare(a, b)