# Parsing a list of single numbers and number ranges

I have input of a string containing a single number (like: $3$) or a range (like: $1-5$). Sample input, all together, looks like: "1-5,3,15-16", and sample output for that input looks like "1,2,3,4,5,15". Output doesn't need to be sorted.

I built something to parse this, but it's ugly. How can I improve this?

from itertools import chain
def giveRange(numString:str):
z=numString.split("-")
if(len(z)==1):
return [int(z[0])]
elif(len(z)==2):
return list(range(int(z[0]),int(z[1])+1))
else:
raise IndexError("TOO MANY VALS!")

def unpackNums(numString:str):
rList=[]
rList.extend(set(chain(*map(giveRange,numString.split(",")))))
return rList
unpackNums("1-2,30-50,1-10")


Disclaimer: I'm not a Python programmer!

Currently, you have this function:

def giveRange(numString:str):
z=numString.split("-")
if(len(z)==1):
return [int(z[0])]
elif(len(z)==2):
return list(range(int(z[0]),int(z[1])+1))
else:
raise IndexError("TOO MANY VALS!")


Why don't you simply store the length in a variable?

Like this:

length=len(z)
if(length==1):
return [int(z[0])]
elif(length==2):
return list(range(int(z[0]),int(z[1])+1))
else:
raise IndexError("TOO MANY VALS!")


Now, you don't have to calculate the length twice, only once.

The name z is a really bad name. Better names would be numbers, pieces or something similar.

Looking at the definition of chain(), it seems to accept any iterable, which a range() happens to be. So, you probably don't need that list(), leaving this:

return range(int(z[0]),int(z[1])+1)


On your function unpackNums instead of creating an empty set(), you could use the a set comprehension:

def unpackNums(numString:str):
return {x for x in set(chain(*map(giveRange,numString.split(","))))}


If you notice any inaccuracies, please comment.

Since the whole exercise is a string-transformation problem, I suggest performing it using a regex substitution.

import re

def expand_ranges(s):
return re.sub(
r'(\d+)-(\d+)',
lambda match: ','.join(
str(i) for i in range(
int(match.group(1)),
int(match.group(2)) + 1
)
),
s
)


I think that expand_ranges would be a more descriptive name than unpackNums.