У меня есть следующий код, в котором я пытаюсь преобразовать строковое представление диапазонов в список чисел. Например, если входное значение равно '0-0,3-5,7-10', ожидаемое значение равно [0,3,4,5,7,8,9,10]. Тем не менее, я получил ошибку в:

for l,h in r.split('-') 

Который говорит, что недостаточно значений для распаковки. Я считаю, что r должен иметь форму 'x-y', поэтому, если я разделю его на '-', я получу два значения обратно. Что в этом плохого?

def parse_ranges(ranges):
    """Return a list of numbers corresponding to number ranges in a string"""
    g = (
        (l,h)
        for r in ranges.split(',')
        for l,h in r.split('-')
        )
    return (x
            for range_tuple in g
            for l,h in range_tuple
            for x in range(int(l), int(h)+1)
            )

parse_ranges('0-5,8-10,11-13')
0
Yilei Huang 8 Июл 2019 в 01:26

4 ответа

Лучший ответ

У тебя слишком много петель. Поскольку вы пытаетесь объединить два числа, вам не нужен второй вложенный цикл. Второй сводит результаты:

>>> [x for r in s.split(',') for x in r.split('-')]
['0', '0', '3', '5', '7', '10']

Используйте один для сохранения парных чисел:

>>> [r.split('-') for r in s.split(',')]
[['0', '0'], ['3', '5'], ['7', '10']]

Затем со вторым пониманием вы можете объединить первые два цикла for, распаковав l и h на месте.

return (x
        for l,h in g
        for x in range(int(l), int(h)+1)
        )
1
John Kugelman 7 Июл 2019 в 22:32

Я не смог понять, как избежать разделения каждой строки диапазона дважды, но с этой небольшой неэффективностью, вот как это можно сделать в одном выражении:

def parse_ranges(ranges):
    return tuple(x for r in
                    (range(int(pair.split('-')[0]), int(pair.split('-')[1])+1)
                        for pair in
                            ranges.split(',')) for x in r)

print(parse_ranges('0-0,3-5,7-10'))  # -> (0, 3, 4, 5, 7, 8, 9, 10)
0
martineau 8 Июл 2019 в 02:09

Для этого есть модуль intspan.

import intspan
s =  '0-0,3-5,7-10'

>>> list(intspan.intspan(s))
[0, 3, 4, 5, 7, 8, 9, 10]
1
Chris Charley 7 Июл 2019 в 22:37

Если ваша цель состоит в том, чтобы разобрать строки с этим форматом в список целых чисел, то, возможно, стоит использовать регулярное выражение для его разбора.

def parse_ranges(ranges):
    """Return a list of numbers corresponding to number ranges in a string"""
    return re.split(',|-', ranges)

parse_ranges('0-5,8-10,11-13')

Выходы:

['0', '5', '8', '10', '11', '13']

Чтобы получить их как целые, а не как строки, вы можете сделать следующее:

def parse_ranges(ranges):
    """Return a list of numbers corresponding to number ranges in a string"""
    return (int(x) for x in re.split(',|-', ranges))

list(parse_ranges('0-5,8-10,11-13'))

Выходы:

[0, 5, 8, 10, 11, 13]
0
Will Da Silva 7 Июл 2019 в 22:34