tags:

views:

210

answers:

9

I want to convert a list like this

l1 = [1,2,3,4,5,6,7,8]

to

l2 = [(1,2),(3,4),(5,6),(7,8)]

because want to loop

for x,y in l2:
    draw_thing(x,y)
A: 

What's wrong with just accessing the correct index and incrementing?

for (int i=0;i<myList.Length;i++)
{
  draw_thing(myList[i],myList[++i]);
}

Oops - sorry, in C# mode. I'm sure you get the idea.

Wim Hollebrandse
He asked for the answer in Python :P
Dana
My bad. Well, the idea is clear I hope.
Wim Hollebrandse
didnt you know? everything in python has to be in 1 line. even if that line is 300 chars long
Shawn Simon
list indexes are dirty and distasteful
recursive
A: 

You can do:

l2 = []
for y in range(0, len(l1), 2):
    l2.append((l1[y], l1[y+1]))

I'm not doing any checks to make sure l1 has an even number of entries and such-like.

Dana
A: 

Not the most elegant solution

l2 = [(l1[i], l1[i+1]) for i in xrange(0,len(l1),2)]
shylent
+8  A: 

One good way is:

from itertools import izip
it = iter([1, 2, 3, 4])
for x, y in izip(it, it):
    print x, y

Output:

1 2
3 4
>>>
Nick D
Damn, this IS good.
shylent
Never thought of using a single iterator twice to zip... that's slick. For the finishing touch you'd want to use `from itertools import izip` to avoid making an extra copy.
Steve Losh
One more change: `zip(*[iter(the_list)]*2)` (or `*3` for 3-tuples, etc).
Steve Losh
@Steve Losh, thanks for the suggestion :)
Nick D
A: 

No need to construct a new list. You can just iterate over the list by steps of 2 instead of 1. I use len(L) - 1 as the upper-bound so you ensure that you don't try to access past the end of the list.

for i in range(0, len(L) - 1, 2):
    draw_thing(L[i], L[i + 1])
jamessan
+7  A: 

Building on Nick D's answer:

>>> from itertools import izip
>>> t = [1,2,3,4,5,6,7,8,9,10,11,12]
>>> for a, b in izip(*[iter(t)]*2):
...     print a, b
...
1 2
3 4
5 6
7 8
9 10
11 12
>>> for a, b, c in izip(*[iter(t)]*3):
...     print a, b, c
...
1 2 3
4 5 6
7 8 9
10 11 12
>>> for a, b, c, d in izip(*[iter(t)]*4):
...     print a, b, c, d
...
1 2 3 4
5 6 7 8
9 10 11 12
>>> for a, b, c, d, e, f in izip(*[iter(t)]*6):
...     print a, b, c, d, e, f
...
1 2 3 4 5 6
7 8 9 10 11 12
>>>

Not quite as readable, but it shows a compact way to get any size tuple you want.

Steve Losh
Thanks for all good answers! Itertools was new for me.
lgwest
+2  A: 

Take a look at grouper function from itertools docs.

from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

In your case use it like this:

l1 = [1,2,3,4,5,6,7,8]
for (x, y) in grouper(2, l1):
    draw_thing(x, y)
Daniel Hernik
Essentially just a long-hand version of what Steve Losh wrote.
ephemient
Right, I didn't saw his answer. But it's not exactly the same. This version may be usefull, when lenght of the list isn't dividable by amount of items you want to process in the loop.
Daniel Hernik
+1 I like this version, it's clearer, works with other lengths as you said, and is already on the docs.
nosklo
+5  A: 

Kind of easy with python's slicing operator:

l2 = zip(l1[0::2], l1[1::2])
Michael
A: 
 list = [1,2,3,4,5,6]
 it = iter(list)
 newlist = [(x, y) for x, y in zip(it, it)]
Tendayi Mawushe
You're iterating over (and unpacking) the tuples returned by `zip` to create a list of identical tuples. In Python 2 the list comprehension is superfluous, and in Python 3 you can just call `list`.
Stephan202