[edit] I'm not sure if this better off to codereview, if so, please migrate :) thanks!
So we were sitting here, working on a semi-academic problem.
Given a start, stop and step, generate a list of range tuples, so that
gen_range(100, 140, 10)
would produce
[(100, 110), (110, 120), (120, 130), (130, 140)]
also, given then fact that it should work on, say, iterating 500M integers with a step of 100 and not take forever.
The implementation I've come up with is as follows:
def gen_range(start, stop, step):
    llist = range(start, stop+step, step)
    batch_list = []
    if llist[-1] > stop:
        llist[-1] = stop
    for a, b in enumerate(llist[:-1]):
        batch_list.append((llist[a], llist[a+1]))
    print batch_list
gen_range(100000000,600000000,100)
But I can't stop thinking that it can be done in a more efficient (also code-length wise) way. Any suggestions?
[edit]
One thing I forgot to point out. If the range boundary is not equal to the step, i.e. you have a case of:
gen_range(100, 143, 10)
the upper boundary should be 143, and not 150, as some answers here would produce, due to range() internals.
Maybe code-length wise if (b - a) % c == 0:
def gen_range(a, b, c):
    return [(i, i + c) for i in range(a, b, c)]
or
def gen_range_2(a, b, c):
    s = range(a, b + c, c)
    return zip(s, s[1:])
See http://ideone.com/VhY215
If (b - a) % c != 0:
def gen_range(a, b, c):
    return [(i, i + c) for i in range(a, b - ((b - a) % c), c)]
or
def gen_range_2(a, b, c):
    s = range(a, b - ((b - a) % c) + c, c)
    return zip(s, s[1:])
See http://ideone.com/i3Pq69
ranges = [(n, min(n+step, stop)) for n in xrange(start, stop, step)]
Perhaps via a generator?
def gen_range(start, stop, step):
    current = start
    while current < stop:
        next_current = current + step
        if next_current < stop:
            yield (current, next_current)
        else:
            yield (current, stop)
        current = next_current
Calling this function gives you a generator object that will produce each of the tuples in order. You would use it like this:
for block in gen_range(100000000,600000000,100):
    print block
which would output...
(100000000,100000100)
(100000100,100000200)
(100000200,100000300)
...
(599999900,600000000)
You could do this even more simply with a generator expression if you're always certain that stop-start is an even multiple of the step:
ranges = ((n, n+step) for n in xrange(start, stop, step))
# Usage
for block in ranges:
    print block
Also note that if you want to turn a generator into a list, holding the entirety of the results in memory, you can simply pass it to list():
all_ranges = list(gen_range(100000000,600000000,100))
                        something like this:
In [48]: it=iter(xrange(100,200,10))
In [49]: it1=iter(xrange(110,210,10))
In [50]: [(next(it),next(it1)) for _ in range(10)]
Out[50]: 
[(100, 110),
 (110, 120),
 (120, 130),
 (130, 140),
 (140, 150),
 (150, 160),
 (160, 170),
 (170, 180),
 (180, 190),
 (190, 200)]
or using zip():
In [55]: it=iter(xrange(100,200,10))
In [56]: it1=iter(xrange(110,210,10))
In [57]: [(x,y) for x,y in zip(it,it1)]
Out[57]: 
[(100, 110),
 (110, 120),
 (120, 130),
 (130, 140),
 (140, 150),
 (150, 160),
 (160, 170),
 (170, 180),
 (180, 190),
 (190, 200)]
                        I'd make it a generator so it could handle huge ranges.
def gen_range(start, stop, step):
    a, b = start, start+step
    while b <= stop:
        yield a, b
        a, b = b, b+step
print list(gen_range(100, 140, 10))
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With