Wednesday, 15 July 2009

Reversing Lines In A File

As is often the case, an interesting little text manipulation task came up in the office today; given a file containing lines of text, reverse it (i.e. put the last line first, the penultimate line second, etc.)

I have a feeling there's a neat little command-line utility that already does this (but can't remember what it is...), but my mind soon went to a short Python script. Here's my first stab at this:

#!/usr/bin/env python
import sys

lines = []
for line in open(sys.argv[1]):
lines.append(line.strip())

lines.reverse()
for line in lines:
print line


After this, I tried to shorten it a bit. Putting the lines into a list could be done nicely with a list comprehension,

#!/usr/bin/env python
import sys

lines = [line.strip() for line in open(sys.argv[1])]

lines.reverse()
for line in lines:
print line


Finally, I discovered the reversed() function, which allows you to create reverse iterators for any Python sequence. Here's where the list comprehension and Python's iteration stuff really comes into its own, leading to a wonderful two-liner (not counting the module import and the #!)


#!/usr/bin/env python
import sys
for line in reversed([line.strip() for line in open(sys.argv[1])]):
print line

6 comments:

  1. I wonder if C# has the equivalent function... If not: to the Visual Studio 2008 cave!

    ReplyDelete
  2. I would imagine C# has reverse iterators. If not, it is severely lacking!

    ReplyDelete
  3. See: http://bytes.com/groups/net-c/449110-can-you-run-foreach-reverse-order. As it happens, C# has no reverse iterator.

    There is a particular post in that thread where it is argued that a network stream may have no end, and therefore cannot be reverse iterated (?) - which, I suppose, is a valid point.

    However, the user then gives an example of an iterator producing prime numbers... That particular example ranks very highly on my "List Of Completely Invalid Examples."

    ReplyDelete
  4. Well... what you were missing is tac.

    The reverse of cat : print in reverse.

    Try :

    echo "Lewd did I live, \n & evil I did dwel" | tac | rev

    for checking multiline palindromes...

    ReplyDelete
  5. I knew there was a command for it! Couldn't for the life of me think what it was, though in retrospect I should have tried the reverse of cat... Thanks!

    ReplyDelete