linusx
linusx

Reputation: 33

Reorder Lines in a Text File (Loop Assistance)

A have a fairly large text file that I need to reorder the lines such as....

line1
line2
line3

Reordered to look like this

line2
line1
line3

File will continue with more lines and the same reordering must occur. I'm stuck and need a loop to do this. Unfortunately, I have hit a speed bump.

with open('poop.txt') as fin, open('clean330.txt', 'w') as fout:
     for line in fin:
          ordering = [1, 0, 2]
          for idx in ordering: # Write output lines in the desired order.
               fout.write(line)

Upvotes: 0

Views: 255

Answers (5)

martineau
martineau

Reputation: 123443

Here's a way to do it that makes use of a couple of Python utilities and a helper function to make things relatively easy. If the number of lines in the file isn't an exact multiple of the length of the group you want to reorder, they're left alone—but that could easily be changed that if you desired.

The grouper() helper function is similar—but not identical—to the recipe with one with same name that's shown in in the itertools documentation.

from itertools import zip_longest
from operator import itemgetter


def grouper(n, iterable):
    ''' s -> (s0,s1,...sn-1), (sn,sn+1,...s2n-1), (s2n,s2n+1,...s3n-1), ... '''
    FILLER = object()  # Value which couldn't be in data.
    for result in zip_longest(*[iter(iterable)]*n, fillvalue=FILLER):
        yield tuple(v for v in result if v is not FILLER)


ordering = 1, 0, 2
reorder = itemgetter(*ordering)
group_len = len(ordering)

with open('poop.txt') as fin, open('clean330.txt', 'w') as fout:
     for group in grouper(group_len, fin):
        try:
            group = reorder(group)
        except IndexError:
            pass  # Don't reorder potential partial group at end.
        fout.writelines(group)

Upvotes: 1

Michael Butscher
Michael Butscher

Reputation: 10959

For a single line swap the code can be like:

with open('poop.txt') as fin, open('clean330.txt', 'w') as fout: 
     for idx, line in enumerate(fin):
          if idx == 0:
              temp = line # Store for later
          elif idx == 1:
              fout.write(line) # Write line 1
              fout.write(temp) # Write stored line 0
          else:
              fout.write(line) # Write as is

For repeated swaps the condition can be e. g. idx % 3 == 0 depending on the requirements.

Upvotes: 1

Timus
Timus

Reputation: 11321

If the number of lines is a multiple of 3:

with open('poop.txt') as fin, open('clean330.txt', 'w') as fout:
    while True:
        try:
            in_lines = [next(fin) for _ in range(3)]
            fout.write(in_lines[1])
            fout.write(in_lines[0])
            fout.write(in_lines[2])
        except StopIteration:
            break

Upvotes: 2

James
James

Reputation: 36608

You can read in 3 lines at a time.

with open('poop.txt') as fin, open('clean330.txt', 'w') as fout:
    line1 = True
    while line1:
        line1 = fin.readline()
        line2 = fin.readline()
        line3 = fin.readline()
        fout.write(line2)
        fout.write(line1)
        fout.write(line3)

Upvotes: 1

Frank Yellin
Frank Yellin

Reputation: 11240

Look at the function grouper in itertools documentation. You then need to do something like:

for lines in grouper(3, fin, '')
    for idx in [1, 0, 2]:
        fout.write(lines[idx])

You haven't specified what you want to do if the input file doesn't have an exact multiple of 3 lines. This code uses blanks.

Upvotes: 1

Related Questions