Reputation: 3
def listOfLists(ntimes,lines,list_val):
a = []
i = 0
j = 0
if ntimes >= lines:
inner_loop = ntimes
outer_loop = lines
else:
inner_loop = lines
outer_loop = ntimes
while i < outer_loop:
while j < inner_loop+i:
if (j*inner_loop-i < len(list_val)):
a.append(list_val[j*inner_loop-i])
j=j+1
else:
j=1
a.append(list_val[j*inner_loop-i])
break
j = i+1
i = i+1
print a
y = [a[x:x+ntimes] for x in range(0, len(a), ntimes)]
print y
What I'd like is a list with sublists whose number of elements is ntimes and lines is the number of sublists. If input is like listOfLists(2,3,[1,2,3,4,5,6])
then output should be:
[[1,4],[2,5],[3,6]]
I'm currently getting:
[[1, 4], [4, 3], [6, 3]]
How can I fix my code to achieve this?
Upvotes: 0
Views: 49
Reputation: 44112
Following code works if the length of lst
is multiplication of lines
>>> lst = [1, 2, 3, 4, 5, 6]
>>> lines = 3
>>> zip(*zip(*[iter(lst)]*lines))
[(1, 4), (2, 5), (3, 6)]
This magic is derived from grouper
mentioned by wim.
Have a list of values
>>> lst = [1,2,3,4,5,6]
Create an iterator over list values:
>>> iter(lst)
<listiterator at 0x7f641480d490>
Note: iterator is able to yield item by item from itself, in this case it is ready to yield item by item from the lst
Create list containing one iterator:
>>> [iter(lst)]
[<listiterator at 0x7f641480d750>]
The list is mutable structure, so even when referenced from multiple variables, it still refers to the same data structure in memory. If any of these refernces uses the iterator inside, the iterator is modified for all the references to this list.
Now create multiplication of the list, multiplying by number of expected lines.
>>> [iter(lst)] * 3
[<listiterator at 0x7f641480dc50>,
<listiterator at 0x7f641480dc50>,
<listiterator at 0x7f641480dc50>]
Note, that all the iterators are showing the same address, all three items in this list are refering to the same iterator.
Now the filan step, zipping it all togather:
>>> zip(*[iter(lst)] * 3)
[(1, 2, 3), (4, 5, 6)]
It could be rewritten as:
zip(*[<listiterator at 0x7f641480dc50>, <listiterator at 0x7f641480dc50>, <listiterator at 0x7f641480dc50>])
what translates (via dereferencing by *
) to:
>>> zip(<listiterator at 0x7f641480dc50>, <listiterator at 0x7f641480dc50>, <listiterator at 0x7f641480dc50>)
[(1, 2, 3), (4, 5, 6)]
The zip
works in the way, it asks each of the iterators to provide one value and creates a tuple
from these 3 values. The trick is, that each request for a value from the iterator consumes it from
all the references, so next time it asks any of iterators, next value will come.
The final step is doing final zipping:
zip(*[(1, 2, 3), (4, 5, 6)])
translates to:
zip((1, 2, 3), (4, 5, 6))
and we have the result:
[(1, 4), (2, 5), (3, 6)]
Upvotes: 0
Reputation: 7555
You can do this:
def listOfLists(ntimes, lines, list_val):
return zip(*zip(*(iter(list_val),) * lines))
Output:
[(1, 4), (2, 5), (3, 6)]
Upvotes: 0
Reputation: 362786
Using the grouper
recipe from itertools
:
>>> L
[1, 2, 3, 4, 5, 6]
>>> zip(*grouper(L, 3))
[(1, 4), (2, 5), (3, 6)]
The zip gives you tuples inside. If you need lists for some reason, transform with a comprehension:
>>> [list(t) for t in _]
[[1, 4], [2, 5], [3, 6]]
Upvotes: 1