Search code examples
pythonreadability

Readable way to form pairs while available


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.


Solution

  • 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)]