6

[1, 109, 2, 109, 2, 130, 2, 131, 2, 132, 3, 28, 3, 127] I have this array and I want to turn it into a list of tuples, each tuple has 2 values in. so this list becomes [(1, 109), (2, 109), (2, 130), (2, 131), (2, 132), (3, 28), (3, 127)]

miik
  • 663
  • 1
  • 8
  • 23
  • Related: http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python – Jon Clements Apr 06 '13 at 15:02
  • This related issue is about generating a list of **lists**, so it is not an exact duplicate, but it's pretty close, and easy to adapt – oefe Apr 06 '13 at 20:02

4 Answers4

12

You can use zip combined with slicing to create a new list of tuples.

my_new_list = zip(my_list[0::2], my_list[1::2])

This would generate a new list with the following output

[(1, 109), (2, 109), (2, 130), (2, 131), (2, 132), (3, 28), (3, 127)]

The process behind this is quite simple. We first split the existing list into two new lists using slicing.

print my_list[0::2] # [1, 2, 2, 2, 2, 3, 3]
print my_list[1::2] # [109, 109, 130, 131, 132, 28, 127]

Then use zip to combine these two lists into one list of tuples.

print zip(my_list[0::2], my_list[1::2])
eandersson
  • 25,781
  • 8
  • 89
  • 110
9
>>> it = iter(L)
>>> zip(*[it]*2)
[(1, 109), (2, 109), (2, 130), (2, 131), (2, 132), (3, 28), (3, 127)]

Explanation

it = iter(L) creates iterator on the initial list

[it]*2 crates the list consisting of the same iterator twice.

* used at the first place in the parameter is used to unpack the parameters, so that zip(*[it]*2) turns into zip(it,it). Though you can use zip(it,it), zip(*[it]*2) is a more general construction, which can be extended to any number of values in the resultant tuple.

The core of this approach is that zip on each iteration tries to get one value from each argument. But it turns out that all the arguments are effectively the same iterator, so it yields every time a new value.

ovgolovin
  • 13,063
  • 6
  • 47
  • 78
  • Super-clever!! +1 for that. But the one trying to understand code including these lines is worse off. – Niklas R Apr 06 '13 at 15:00
  • @NiklasR Yeah, I have been writing explanation after typing the core of the answer. – ovgolovin Apr 06 '13 at 15:01
  • It looks very nice, but unfortunately it relies on the fact that `zip` takes values from the iterators left to right, which may be logical considering its output, but is actually an implementation detail. – Thijs van Dien May 02 '13 at 17:27
2

Another approach:

lst = [1, 109, 2, 109, 2, 130, 2, 131, 2, 132, 3, 28, 3, 127]

print [(lst[i], lst[i + 1]) for i in xrange(0, len(lst), 2)]
#[(1, 109), (2, 109), (2, 130), (2, 131), (2, 132), (3, 28), (3, 127)]
BrtH
  • 2,610
  • 16
  • 27
0

Inspired by ovgolovin's answer:

>>> it=iter(L)
>>> [(el, next(it)) for el in it]
[(1, 109), (2, 109), (2, 130), (2, 131), (2, 132), (3, 28), (3, 127)]

May be a little easier to see how it works. Can also reverse the tuple order:

>>> it=iter(L)
>>> [(next(it), el) for el in it]
[(109, 1), (109, 2), (130, 2), (131, 2), (132, 2), (28, 3), (127, 3)]
dansalmo
  • 11,506
  • 5
  • 58
  • 53