Есть числа по порядку, но с пропусками. Как получить интервалы?

Есть некий интервал чисел с пропусками, например: 1, 2, 3, 5, 6, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20. Как получить вместо списка интервалы: 1-3, 5-7, 9-12, 15-20 ?


Ответы (2 шт):

Автор решения: GrAnd

Вот так можно:

import itertools

numbers = [1, 2, 3, 5, 6, 7, 9, 10, 12, 15, 16, 17, 18, 19, 20, 25]

ranges = [[r[0][1], r[-1][1]][:len(r)] for r in [list(x) for _, x in itertools.groupby(enumerate(numbers), lambda en: en[0] - en[1])]]
print("List   :", ranges) 
ranges_str = ", ".join("-".join(map(str, r)) for r in ranges)
print("String :", ranges_str)
D:\Programming\Python\1>python compact_range.py
List   : [[1, 3], [5, 7], [9, 10], [12], [15, 20], [25]]
String : 1-3, 5-7, 9-10, 12, 15-20, 25
→ Ссылка
Автор решения: Stanislav Volodarskiy

Функция events выдаёт наружу события. В события включаются концы последовательности чисел и пары чисел окружающих дыры.

Функция ranges соединяет события в пары. Эти пары и есть ответ:

def events(seq):
    it = iter(seq)
    try:
        p = next(it)
    except StopIteration:
        return
    yield p
    for v in it:
        if p < v - 1:
            yield p
            yield v
        p = v
    yield p


def ranges(seq):
    return zip(*[iter(events(seq))] * 2)


values = 1, 2, 3, 5, 6, 7, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20
print(*events(values))
print(*ranges(values))
$ python ranges_in_list.py 
1 3 5 7 9 12 15 20
(1, 3) (5, 7) (9, 12) (15, 20)
→ Ссылка