我有一个整数列表,我需要解析为一系列范围.
例如:
[0, 1, 2, 3] -> "0-3"
[0, 1, 2, 4, 8] -> "0-2,4,8"
Run Code Online (Sandbox Code Playgroud)
等等.
我还在学习更多pythonic处理列表的方法,这对我来说有点困难.我最近的想法是创建一个列表,跟踪配对数字:
[ [0, 3], [4, 4], [5, 9], [20, 20] ]
Run Code Online (Sandbox Code Playgroud)
然后,我可以遍历此结构,将每个子列表打印为范围或单个值.
我不喜欢在两次迭代中这样做,但我似乎无法跟踪每次迭代中的每个数字.我的想法是做这样的事情:
这是我最近的尝试.它有效,但我并不完全满意; 我一直在想,有一个更优雅的解决方案完全逃脱了我.字符串处理迭代不是最好的,我知道 - 对我来说这是很早的:)
def createRangeString(zones):
rangeIdx = 0
ranges = [[zones[0], zones[0]]]
for zone in list(zones):
if ranges[rangeIdx][1] in (zone, zone-1):
ranges[rangeIdx][1] = zone
else:
ranges.append([zone, zone])
rangeIdx += 1
rangeStr = ""
for range in ranges:
if range[0] != range[1]:
rangeStr = "%s,%d-%d" % (rangeStr, range[0], range[1])
else:
rangeStr = "%s,%d" % (rangeStr, range[0])
return rangeStr[1:]
Run Code Online (Sandbox Code Playgroud)
有没有一种简单的方法可以将它合并到一个迭代中?我还能做些什么才能让它更像Pythonic?
Joh*_*ooy 21
>>> from itertools import count, groupby
>>> L=[1, 2, 3, 4, 6, 7, 8, 9, 12, 13, 19, 20, 22, 23, 40, 44]
>>> G=(list(x) for _,x in groupby(L, lambda x,c=count(): next(c)-x))
>>> print ",".join("-".join(map(str,(g[0],g[-1])[:len(g)])) for g in G)
1-4,6-9,12-13,19-20,22-23,40,44
Run Code Online (Sandbox Code Playgroud)
这里的想法是将每个元素与count()配对.然后,值和count()之间的差值对于连续值是恒定的.groupby()完成剩下的工作
正如杰夫建议的那样,另一种选择count()就是使用enumerate().这增加了一些需要在print语句中删除的额外内容
G=(list(x) for _,x in groupby(enumerate(L), lambda (i,x):i-x))
print ",".join("-".join(map(str,(g[0][1],g[-1][1])[:len(g)])) for g in G)
Run Code Online (Sandbox Code Playgroud)
更新:对于此处给出的示例列表,具有枚举的版本比我在计算机上使用count()的版本运行速度慢约5%