-1

I'm trying to turn a list into pairs, but only for as long as possible (i.e. my list can be odd, in that case I want to ignore the last element).

E.g. my input is x = [0, 1, 2, 3, 4], which I would want to turn into [(0, 1), (2, 3)]. Similarly, x = [0, 1, 2, 3, 4, 5] should become [(0, 1), (2, 3), (4, 5)].

What I'm currently doing is [(x[i], x[i+1]) for i in range(0, len(x), 2)]. This breaks, as range(0, len(x), 2) still includes x[-1] if len(x) is odd. Note that something of the form [(l, r) for l, r in ...] would also be preferable, rather than having to fiddle with indices.

Bonus points: Here's some more context. I'm not completely ignoring the last element of an odd sequence, of course. I'm applying a function to each pair, but I do not want to apply this function H to the singleton element. Currently, I'm doing the following:

next_layer = [H(layer[i], layer[i+1]) for i in range(0, len(layer), 2)]
if len(layer) & 1:  # if there is a lone node left on this layer
    next_layer.append(layer[-1])

An extra elegant solution would incorporate this into the above as well.

Joost
  • 4,094
  • 3
  • 27
  • 58
  • I came across that question, but I felt like this one differed on specifics and the answers were not satisfying. I suppose I didn't evaluate it properly. – Joost Oct 13 '15 at 10:15

1 Answers1

2

Use a zip

This function returns a list of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. The returned list is truncated in length to the length of the shortest argument sequence.

>>> a = [1, 2, 3, 4, 5]
>>> b = [0, 1, 2, 3, 4, 5]
>>> zip(a[::2], a[1::2])
[(1, 2), (3, 4)]
>>> zip(b[::2], b[1::2])
[(0, 1), (2, 3), (4, 5)]
luoluo
  • 5,353
  • 3
  • 30
  • 41
  • I.. Am dumbfounded. I started out with something like this, and ended up diverging. It seems I need to go full circle. Now using `[H(l, r) for l, r in zip(layer[::2], layer[1::2])]` and it hit all my test cases correctly. That's pretty readable for people familiar with this notation, I suppose. Will accept once the timer runs out :-) – Joost Oct 13 '15 at 10:11
  • erm, not super readable. Prefer the solution in the duplicate question `zip(*[iter(lst)] * 2)` – Adam Smith Oct 13 '15 at 10:26
  • While that is shorter, more flexible (e.g. when using generators) and likely more efficient, it does require unpacking an argument list and multiplying the list of iterators.. Not immediately obvious what is happening, imo. – Joost Oct 13 '15 at 11:05
  • If you don't mind, I'll add your suggestion to my answer @AdamSmith – luoluo Oct 13 '15 at 11:06
  • 1
    @luoluo I don't mind, but it's not really necessary. This question is already a duplicate of (hundreds of) others and is pointing towards the canonical. Joost you're right that it's not immediately obvious, but consider that an idiom in Python. It's common to see that idiom used to group an iterator. It's ever referred to in the itertools docs page – Adam Smith Oct 13 '15 at 11:14