Generating pairs from range

I have a range of integers spanning from x to y, where x >= 0, y > x. I also have a step-size z, where z > 0, x % z == 0, y % z == 0.

I want a sequence of two-tuples like so:

(x, x + z)
(x + z, x + 2*z)

(x + n * z, y)

Is there a more elegant way to generate this sequence than:

``````[(i, j) for i, j in zip(range(x, y, z), range(x+z, y+z, z))]
``````

The reason I’m looking for another way to spell this is that `zip(range(x, y, z), range(x+z, y+z, z))` gets very long when using more descriptive variable names than `x, y, z`.

If I’m understanding you correctly, the two ranges here are identical except that the second range is precisely `z` higher - or, looking at it another way, you could take the combined range, then slice off the first and slice off the last to make the two ranges.

In that case, what I’d do would be:

``````span = range(x, y+z, z)
[(i, j) for i, j in zip(span[:-1], span[1:])]
``````

All of the details of the breadth of the span are handled first, and then the pairing up happens afterwards.

1 Like

That works, thanks!

Let’s see if anyone can golf it shorter still

2 Likes

Why does this not work?

``````[(i, i + z) for i in range(x, y, z)]
``````
2 Likes

It does! So obvious too, now I feel dumb. Must be a case of Friday afternoon

“pairs from range”, you say?

``````from itertools import pairwise

list(pairwise(range(x, y + 1, z)))
``````
7 Likes

whoops, I misunderstood the goal at first. But I’ll still edit Chris’s suggestion

“unnecessary comprehension” is Python’s version of useless use of cat

4 Likes

Indeed. That’s what happens when you edit a few times in search of an elegant solution, and end up with one that’s quirkily inelegant

3 Likes

Note that we can omit slicing off the last item when `zip` can do it for us:

``````list(zip(span, span[1:]))
``````
3 Likes

And note they mentioned “gets very long when using more descriptive variable names than x, y, z”, so you might want to use `y+1` instead of `y+z`.

2 Likes