Разбивка списка номеров на диапазоны

Есть список номеров в Excel-файле, необходимо сократить его до диапазонов номеров, но только до полных 10, 100, 1000 и т.д.
Например, из

3012275120
3012275121
3012275122
3012275123
3012275124
3012275125
3012275126
3012275127
3012275128
3012275129

Надо сделать 301227512*
А номера, которые не попадают в диапазоны оставить как есть.
Желательно на Python


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

Автор решения: Stanislav Volodarskiy

Достаточно сложное решение получилось. Проще не придумал. Пока значения из seq следуют без разрывов, очередь queue накапливает значения. Например, предыдущее число было 2987 и содержимое очереди:

queue == [
    [2980, 2981, 2982, 2983, 2984, 2985, 2986, 2987],
    [290, 291, 292, 293, 294, 295, 296, 297],
    [20, 21, 22, 23, 24, 25, 26, 27, 28],
    []
]

Нулевая строка очереди хранит накопленные значения для единиц, следующая для десятков, дальше сотни и так далее. Например значение 21 в разряде сотен соответствует группе 21**.

Следующее значение 2988 добавляется в разряд единиц:

queue == [
    [2980, 2981, 2982, 2983, 2984, 2985, 2986, 2987, 2988],
    [290, 291, 292, 293, 294, 295, 296, 297],
    [20, 21, 22, 23, 24, 25, 26, 27, 28],
    []
]

Если значение заканчивается на девятку и разряд заполнился до десяти значений, он удаляется, в следующий разряд добавляется значение. Следующее значение 2989 меняет очередь:

queue == [
    [],
    [290, 291, 292, 293, 294, 295, 296, 297, 298],
    [20, 21, 22, 23, 24, 25, 26, 27, 28],
    []
]

Эта группировка и перенос делается в цикле. В случае разрыва нумерации или окончания последовательности группы из очереди печатаются, сама очередь очищается.

def ranges(seq):

    queue = []
    
    def drop_queue():
        for i in range(len(queue))[::-1]:
            for r in queue[i]:
                yield f'{r}{"*" * i}'
        queue[:] = []

    prev = 0
    for v in seq:
        if v != prev + 1:
            yield from drop_queue()
        prev = v

        if not queue or queue[-1]:
            queue.append([])

        for line in queue:
            line.append(v)
            if v % 10 != 9:
                break
            if len(line) == 10:
                line[:] = []
                v //= 10
            else:
                yield from drop_queue()
                break

    yield from drop_queue()

Примеры:

for r in ranges([
    3012275120, 3012275121, 3012275122, 3012275123, 3012275124,
    3012275125, 3012275126, 3012275127, 3012275128, 3012275129
]):
    print(r)
301227512*
for r in ranges(range(1888, 3222)):
    print(r)
1888
1889
189*
19**
2***
30**
31**
320*
321*
3220
3221
→ Ссылка