1

I am writing a script to swap several items in some lists read from a *.txt file, I tried to write it like this:

i_file = map(lambda x: x.split('|'), open('test.txt', 'r').readlines())
for list in i_file:
    list = [list[2], list[0], list[3], list[1], list[4:]]
    #Actually I want to update the i_file, but I don't think this will work here
    #nevermind, it's just a demostration.

It looks so ugly and hard to read, so I am looking for

 somefunc()

that might make my code look like this.

i_file = map(lambda x: x.split('|').somefunc(), open('test.txt', 'r').readlines())

Thanks!!

UPDATE:

input file looks like this:

blahblah1|3141593|Wednesday|John|BlahBlah1|
blahblah2|2714323|Monday|Mike|BlahBlah2|

I want to swap these items in each line in order to rewrite the file into:

3141593|Wednesday|blahblah1|John|BlahBlah1|
blahblah2|Monday|2714323|Mike|BlahBlah2|
7O'clock
  • 41
  • 9
  • Please post some sample input and describe how the items should be joined in the output. –  Mar 01 '12 at 08:55
  • See here: http://stackoverflow.com/questions/2177590/how-can-i-reorder-a-list-in-python – sleeplessnerd Mar 01 '12 at 08:58
  • @sleeplessnerd I can understand this method, but I am trying to avoid loops you see... Or I have to write it in two lines? thx~ – 7O'clock Mar 01 '12 at 09:03
  • Your actual wanted output is confusing: the first line swaps to: `[l[1], l[2], l[0]] + l[3:]` and the second to `[l[0], l[2], l[1]] + l[3:]`. Is that what you really want? – Rik Poggi Mar 01 '12 at 09:17
  • @Rik Poggi It's just a demo, the actual file contains more items. – 7O'clock Mar 01 '12 at 09:19
  • @7O'clock I think Rik means it isn't clear what transformation you want to make to each line. You're showing two different transforms. Do you intend to do a different thing for each line in the file? – Peter Wood Mar 01 '12 at 09:24
  • 2
    `list` is a poor choice of variable name, as it hides the builtin reference to the class itself. – Karl Knechtel Mar 01 '12 at 10:53
  • 1
    If your goal is really just to produce the output line (a modified string with '|') and you don't need the list for anything, you might consider just using regular expressions. – Karl Knechtel Mar 01 '12 at 11:01

7 Answers7

3

Python allows you to assign to a list slice, so you can cleanly permute the columns in-place without messing with lambda and map:

out = open("testout.txt", "w")

for line in open('test.txt', 'r').readlines():
    lst = line.split("|")
    lst[0:4] = lst[2], lst[0], lst[3], lst[1]
    out.write("|".join(lst))

You can even insert or delete columns by having more elements on one side of the assignment:

>>> lst = "blahblah1|3141593|Wednesday|John|BlahBlah1|\n".split("|")
>>> lst[0:4] = lst[2], lst[2][:3], lst[0], lst[3], lst[1]
>>> print "|".join(lst)
Wednesday|Wed|blahblah1|John|3141593|BlahBlah1|
alexis
  • 48,685
  • 16
  • 101
  • 161
2

One general approach is to separate the indices and the list:

>>> parts = range(7)
>>> indices = [2, 0, 3, 1] + range(4, 7)
>>> [parts[i] for i in indices]
[2, 0, 3, 1, 4, 5, 6]
Lauritz V. Thaulow
  • 49,139
  • 12
  • 73
  • 92
1

I would simply do the following:

i_file = map(lambda x: x.split('|'), open('test.txt', 'r').readlines())
for l in i_file:
    l[:] = [l[2], l[0], l[3], l[1]] + l[4:]

Notes:

  1. Thanks to the added [:], this code will update i_file.
  2. I've renamed list so that it doesn't shadow the builtin.
  3. I've fixed a bug in the original code whereby l[4:] was made into a sub-list.
NPE
  • 486,780
  • 108
  • 951
  • 1,012
1

You can unpack a list into separate values then reconstitute in a different order:

>>> a, b, c = [1, 2, 3]
>>> [a, c, b]
[1, 3, 2]

So for your code:

>>> line = 'blahblah1|3141593|Wednesday|John|BlahBlah1|'
>>> blah, number, day, name, other_name, empty = line.split('|')
>>> '|'.join([number, day, blah, name, other_name, empty])
'3141593|Wednesday|blahblah1|John|BlahBlah1|'

Or you could use a regular expression:

>>> import re
>>> line = 'blahblah1|3141593|Wednesday|John|BlahBlah1|'
>>> match = re.match(r'(.*)\|(.*)\|(.*)\|(.*)\|(.*)\|', line)
>>> match.expand(r'\2|\3|\1|\4|\5|')
'3141593|Wednesday|blahblah1|John|BlahBlah1|'

Note: I'm not an expert with re, and there may be better ways of doing this.

Peter Wood
  • 23,859
  • 5
  • 60
  • 99
1

The function to do what you want is operator.itemgetter:

>>> lines = ["blahblah1|3141593|Wednesday|John|BlahBlah1|",
...          "blahblah2|2714323|Monday|Mike|BlahBlah2|"]
>>> swap = operator.itemgetter(2, 0, 3, 1, slice(4,None))
>>> map(lambda x: swap(x.split('|')), lines)
[('Wednesday', 'blahblah1', 'John', '3141593', ['BlahBlah1', '']), ('Monday', 'b
lahblah2', 'Mike', '2714323', ['BlahBlah2', ''])]
Michael J. Barber
  • 24,518
  • 9
  • 68
  • 88
1

If you insist on a one-liner using lambda and map:

map(lambda x: (lambda a,b,c,d,*e: list((c,a,d,b) + e))(*x.split('|')), open('test.txt', 'r').readlines())
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
0

You can nest list comprehensions to get what you want. Something like this should do the trick. (untested)

i_file = [ [ y[2], y[0], y[3], y[1] ] + y[4:] for y in [ x.split('|') for x in open('test.txt','r').readlines() ] ]
Michael Anderson
  • 70,661
  • 7
  • 134
  • 187