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")
2 Answers 2
Disclaimer: I'm not a Python programmer!
Your code isn't that bad. It's readable enough for me to understand it. B+ for readability!
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
.
-
1\$\begingroup\$ This solution does not remove duplicate values. An input of
"1-2,30-50,1-10"
will yield an output of1,2,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,1,2,3,4,5,6,7,8,9,10
\$\endgroup\$Android Control– Android Control2023年11月12日 02:35:05 +00:00Commented Nov 12, 2023 at 2:35