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: 265

Answers (5)

martineau
martineau

Reputation: 123531

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: 10969

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: 11371

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: 36791

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: 11330

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