converting a list of integers into range in python

You can use a list comprehension with a generator expression and a combination of enumerate() and itertools.groupby():

>>> import itertools
>>> l = [0, 1, 2, 3, 4, 7, 8, 9, 11]
>>> [[t[0][1], t[-1][1]] for t in
... (tuple(g[1]) for g in itertools.groupby(enumerate(l), lambda (i, x): i - x))]
[[0, 4], [7, 9], [11, 11]]

First, enumerate() will build tuples from the list items and their respective index:

>>> [t for t in enumerate(l)]
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 7), (6, 8), (7, 9), (8, 11)]

Then groupby() will group those tuples using the difference between their index and their value (which will be equal for consecutive values):

>>> [tuple(g[1]) for g in itertools.groupby(enumerate(l), lambda (i, x): i - x)]
[((0, 0), (1, 1), (2, 2), (3, 3), (4, 4)), ((5, 7), (6, 8), (7, 9)), ((8, 11),)]

From there, we only need to build lists from the values of the first and last tuples of each group (which will be the same if the group only contains one item).

You can also use [(t[0][1], t[-1][1]) ...] to build a list of range tuples instead of nested lists, or even ((t[0][1], t[-1][1]) ...) to turn the whole expression into a iterable generator that will lazily build the range tuples on the fly.


Using itertools.groupby() produces a concise but tricky implementation:

import itertools

def ranges(i):
    for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
        b = list(b)
        yield b[0][1], b[-1][1]

print(list(ranges([0, 1, 2, 3, 4, 7, 8, 9, 11])))

Output:

[(0, 4), (7, 9), (11, 11)]