Reputation: 117
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')
Upvotes: 1
Views: 133
Reputation: 123541
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)
Upvotes: 0
Reputation: 6633
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]
Upvotes: 1
Reputation: 7040
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]
Upvotes: 0
Reputation: 362107
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)
)
Upvotes: 1