What's wrong with my use of generator expression?

别来无恙 提交于 2020-06-29 04:17:38

问题


I have the following code, in which I try to convert a string representation of ranges to a list of numbers. For example, if the input is '0-0,3-5,7-10' the expected output is [0,3,4,5,7,8,9,10]. However, I got an error at:

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

which it says not enough values to unpack. My reasoning is that, r should have the form 'x-y', so if I split it by '-', I should get two values back. What's wrong with that?

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')

回答1:


You've got a loop too many. Since you're trying to keep the two numbers together you don't need a second nested loop. The second one is flattening the results:

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

Use one to keep the numbers paired:

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

Then with the second comprehension you can combine the first two for loops by unpacking l and h in place.

return (x
        for l,h in g
        for x in range(int(l), int(h)+1)
        )



回答2:


There is the intspan module which does just that.

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

>>> list(intspan.intspan(s))
[0, 3, 4, 5, 7, 8, 9, 10]



回答3:


If your goal is to parse strings with that format into a list of ints, then it may be worth using a regex to parse it

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')

Outputs:

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

To get them as ints, rather than strings, you could do the following:

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'))

Outputs:

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



回答4:


I've been unable to figure-out how to avoid splitting each range string twice, but with that slight inefficiency, here's how it can be made into a single expression:

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)


来源:https://stackoverflow.com/questions/56926573/whats-wrong-with-my-use-of-generator-expression

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!