解析可选的范围列表
Parsing an optional list of ranges
我的脚本需要采用一个选项,后跟一个页面列表,指定为以逗号分隔的范围列表,并处理扩展的页面列表。所以,例如,
script.py -a 2,4-6,9,10-13
应该得到列表
[2, 4, 5, 6, 9, 10, 11, 12, 13]
一起工作。目前我正在这样做:
import argparse
def getList(argument):
ranges = list(argument.split(","))
newRange = []
for theRange in ranges:
subRange = list(map(int, theRange.split("-")))
if (len(subRange) > 1):
newRange.extend(range(subRange[0], subRange[1] + 1))
else:
newRange.extend(subRange)
newRange.sort()
return newRange
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-a", "--pages", type=getList, dest="pages", default=[], help="pages to process")
args = parser.parse_args()
它有效,但我对这个 Python 比较陌生,想知道是否有更好的方法来做到这一点?
编辑:我不明白为什么它被标记为重复问题。 None 被标记为重复的问题的答案完全符合我上面描述的内容。这个想法是 而不是 来处理一个简单的列表 space- 或逗号分隔的参数,但更复杂的东西 - 一个必须扩展的范围列表。
这是一种解决方案。它不一定是最好的。特别是,可能有一个涉及链式迭代器而不是嵌套迭代器的性能更高的版本。
鉴于:
>>> range='2,4-6,9,10-13'
你可以这样做:
>>> result = [range(int(y[0]), int(y[1])+1)
... for y in [(x.split('-') + [x])[:2]
... for x in r.split(',')]]
哪个让你:
>>> result
[[2], [4, 5, 6], [9], [10, 11, 12, 13]]
如果我们解包这些推导式,最里面的推导式会迭代:
>>> range.split(',')
['2', '4-6', '9', '10-13']
第二个是:
>>> result = range.split(',')
>>> [(x.split('-') + [x])[:2] for x in result]
[['2', '2'], ['4', '6'], ['9', '9'], ['10', '13']]
表达式 (x.split('-') + [x])[:2]
确保我们有一个包含两项的列表,即使是单个数字,这样我们就可以将其传递给 range
函数。
最后,我们迭代该结果:
>>> [range(int(y[0]), int(y[1])+1) for y in <the result from the rpevious operation]
这很明显。给定列表 [2, 2]
,我们调用 range(2, 3)
得到 [2]
。应用于之前操作的所有结果,这让我们得到了我们之前看到的结果:
[[2], [4, 5, 6], [9], [10, 11, 12, 13]]
现在你的问题是 "how do I flatten a list",其中一个解决方案(来自 here)是:
>>> import itertools
>>> list(itertools.chain.from_iterable(result))
[2, 4, 5, 6, 9, 10, 11, 12, 13]
我的脚本需要采用一个选项,后跟一个页面列表,指定为以逗号分隔的范围列表,并处理扩展的页面列表。所以,例如,
script.py -a 2,4-6,9,10-13
应该得到列表
[2, 4, 5, 6, 9, 10, 11, 12, 13]
一起工作。目前我正在这样做:
import argparse
def getList(argument):
ranges = list(argument.split(","))
newRange = []
for theRange in ranges:
subRange = list(map(int, theRange.split("-")))
if (len(subRange) > 1):
newRange.extend(range(subRange[0], subRange[1] + 1))
else:
newRange.extend(subRange)
newRange.sort()
return newRange
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-a", "--pages", type=getList, dest="pages", default=[], help="pages to process")
args = parser.parse_args()
它有效,但我对这个 Python 比较陌生,想知道是否有更好的方法来做到这一点?
编辑:我不明白为什么它被标记为重复问题。 None 被标记为重复的问题的答案完全符合我上面描述的内容。这个想法是 而不是 来处理一个简单的列表 space- 或逗号分隔的参数,但更复杂的东西 - 一个必须扩展的范围列表。
这是一种解决方案。它不一定是最好的。特别是,可能有一个涉及链式迭代器而不是嵌套迭代器的性能更高的版本。
鉴于:
>>> range='2,4-6,9,10-13'
你可以这样做:
>>> result = [range(int(y[0]), int(y[1])+1)
... for y in [(x.split('-') + [x])[:2]
... for x in r.split(',')]]
哪个让你:
>>> result
[[2], [4, 5, 6], [9], [10, 11, 12, 13]]
如果我们解包这些推导式,最里面的推导式会迭代:
>>> range.split(',')
['2', '4-6', '9', '10-13']
第二个是:
>>> result = range.split(',')
>>> [(x.split('-') + [x])[:2] for x in result]
[['2', '2'], ['4', '6'], ['9', '9'], ['10', '13']]
表达式 (x.split('-') + [x])[:2]
确保我们有一个包含两项的列表,即使是单个数字,这样我们就可以将其传递给 range
函数。
最后,我们迭代该结果:
>>> [range(int(y[0]), int(y[1])+1) for y in <the result from the rpevious operation]
这很明显。给定列表 [2, 2]
,我们调用 range(2, 3)
得到 [2]
。应用于之前操作的所有结果,这让我们得到了我们之前看到的结果:
[[2], [4, 5, 6], [9], [10, 11, 12, 13]]
现在你的问题是 "how do I flatten a list",其中一个解决方案(来自 here)是:
>>> import itertools
>>> list(itertools.chain.from_iterable(result))
[2, 4, 5, 6, 9, 10, 11, 12, 13]