user1739685
user1739685

Reputation: 21

PYTHON: alternating reading lines from 2 files and appending to a third

I need to write a function, shuffleFiles(afile, bfile, cfile), that reads a line from file afile then reads a line from file bfile and appends these lines respectively to file C. If either file afile or bfile has been completely read then continue appending lines from the other file into file C.

This is the code I have so far, the lines are not being written to the file, but if i swap them out for print statements the lines print out in the correct order, just with blank \n in between most of them. not sure where to go from here

def shuffleFiles(afile, bfile, cfile):
  fileA = open(afile, 'r')
  fileB = open(bfile, 'r')
  fileC = open(cfile, 'a')
  fileADone = False
  fileBDone = False
while not fileADone or not fileBDone:
    if not fileADone:
        line = fileA.readline()
        line.rstrip()
        line.strip()
        if line == "" or line == " " or line == "/n":
            fileADone = True
        else:
            fileC.write(str(line))
    if not fileBDone:
        line = fileB.readline()
        line.rstrip()
        line.strip()
        if line == "" or line == " " or line == "/n":
            fileBDOne = True
        else:
            fileC.write(str(line))

fileA.close()
fileB.close()
fileC.close()

Upvotes: 2

Views: 273

Answers (1)

Joel Cornett
Joel Cornett

Reputation: 24788

Here's one way to iterate over two alternating iterables (files included):

from itertools import chain, izip_longest

fileA = open('file_A.txt')
fileB = open('file_B.txt')

for line in filter(None, chain.from_iterable(izip_longest(fileA, fileB))):
    #Do stuff here.

The izip_longest "zips" together two or more iterables:

>>> a = [1, 2, 3, 4]
>>> b = ['a', 'b', 'c', 'd', 'e', 'f']
>>> list(izip_longest(a, b))
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (None, 'e'), (None, 'f')]

Then chain.from_iterable chains these into one long running iterable:

>>> list(chain.from_iterable(izip_longest(a, b)))
[1, 'a', 2, 'b', 3, 'c', 4, 'd', None, 'e', None, 'f']

Finally, filter with None as the first argument only returns the values with non-false values. In this case, it serves to filter out the Nones in the list above (Nones will occur when one iterable is longer than another), as well as to filter out '' empty strings that may be present in the files.

>>> filter(None, chain.from_iterable(izip_longest(a, b)))
[1, 'a', 2, 'b', 3, 'c', 4, 'd', 'e', 'f']

EDIT - Thanks to Tadeck

Putting all of this together, along with the more pythonic with operator for opening files, we get something like this:

with open('fileA.txt') as fileA, open('fileB.txt') as fileB, open('fileC.txt') as fileC:
    lines = chain.from_iterable(izip_longest(fileA, fileB, fillvalue=''))
    fileC.writelines(filter(None, (line.strip() for line in lines)))

Upvotes: 1

Related Questions