The answer
s, g1, g2, g3, g4 = [[line.strip() for line in group_of_lines] for group_of_lines in zip(*zip(*[open('marks.txt')]*5))]
How I derived the answer
From the prompt of the ipython
shell:
In [38]: cat marks.txt
s1
g11
g12
g13
g14
s2
g21
g22
g23
g24
s3
g31
g32
g33
g34
In [39]: zip(*[open('marks.txt')]*5)
Out[39]:
[('s1\n', 'g11\n', 'g12\n', 'g13\n', 'g14\n'),
('s2\n', 'g21\n', 'g22\n', 'g23\n', 'g24\n'),
('s3\n', 'g31\n', 'g32\n', 'g33\n', 'g34\n')]
In [40]: zip(*zip(*[open('marks.txt')]*5))
Out[40]:
[('s1\n', 's2\n', 's3\n'),
('g11\n', 'g21\n', 'g31\n'),
('g12\n', 'g22\n', 'g32\n'),
('g13\n', 'g23\n', 'g33\n'),
('g14\n', 'g24\n', 'g34\n')]
In [41]: [[line.strip() for line in group_of_lines] for group_of_lines in zip(*zip(*[open('marks.txt')]*5))]
Out[41]:
[['s1', 's2', 's3'],
['g11', 'g21', 'g31'],
['g12', 'g22', 'g32'],
['g13', 'g23', 'g33'],
['g14', 'g24', 'g34']]
In [42]: s, g1, g2, g3, g4 = [[line.strip() for line in group_of_lines] for group_of_lines in zip(*zip(*[open('marks.txt')]*5))]
In [43]: print '\n'.join(map(str,(s,g1,g2,g3,g4)))
['s1', 's2', 's3']
['g11', 'g21', 'g31']
['g12', 'g22', 'g32']
['g13', 'g23', 'g33']
['g14', 'g24', 'g34']
In [44]:
A line by line commentary on "How I derived the answer"
[38]
My personal version of the marks.txt
data file
[39]
The crux of the procedure, the
grouper
procedure shamelessly adapted from the itertools
module fine
docs.
A file object can be simply understood as an iterator that returns the
file content line by line, so we start with a list containing 5
(identical) copies of a file iterator that returns the content of our
data file, and pass the elements of this list (by using the *
star
operator) to the zip
builtin function, that returns a list of tuples
with an element from each one of its arguments, e.g.:
In [44]: zip(*[[1,2,3],[10,20,30]])
Out[44]: [(1, 10), (2, 20), (3, 30)]
Because zip
is passsed five identical copies of the same file
iterator, it builds a list of tuples containing the first five lines,
the second five lines, ..., of our file.
[40]
But we want it the other way around! Or, in other words, we want to
transpose our list of tuples.
Transposition of a sequence of sequences is usually obtained with an
idiom that's very similar to what we've just seen...
In [45]: zip(*[(1, 10), (2, 20), (3, 30)])
Out[45]: [(1, 2, 3), (10, 20, 30)]
[41]
What's the matter with all these '\n'
newline charaters? Let's strip
them away...
Our problem is that we have a double nesting, say a list of lists
containing the elements that we want to correct...
We have no choice but to unpack the elements with a double loop and
then pack twice our corrected, stripped items again in a list of
lists...
[42]
We have a list of lists, whose elements are exactly what we want to
associate to our variable names, this can be done in one sweep using
what is called _sequence unpacking...
The statement 42 represents the compact solution to our problem. By a long time we all knew that 42 is the answer, now eventually we know the question too...
[43]
Just to verify that what we have in our variables is the result we are
looking for.