我有一个整数列表,需要将其解析为一系列字符串。
例如:
[0, 1, 2, 3] -> "0-3" [0, 1, 2, 4, 8] -> "0-2,4,8"
等等。
我仍在学习处理列表的更多pythonic方法,这对我来说有点困难。我最近的想法是创建一个列表列表,以跟踪成对的数字:
[ [0, 3], [4, 4], [5, 9], [20, 20] ]
然后,我可以遍历此结构,将每个子列表打印为范围或单个值。
我不喜欢在两次迭代中执行此操作,但是我似乎无法跟踪每次迭代中的每个数字。我的想法是做这样的事情:
这是我最近的尝试。它有效,但是我并不完全满意;我一直在想,有一个更优雅的解决方案完全让我无法幸免。我知道,字符串处理迭代并不是最好的方法- 对我来说这是一大清早:)
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:]
有没有简单的方法可以将其合并为单个迭代?我还能做些什么使它变得更Pythonic?
>>> 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
这里的想法是将每个元素与count()配对。然后,对于连续值,该值与count()之间的差是恒定的。groupby()完成其余工作
正如Jeff所建议的那样,count()可以使用替代方法enumerate()。这增加了一些多余的杂物,需要在print语句中删除
count()
enumerate()
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)
更新: 对于此处给出的示例列表,带有枚举的版本比我计算机上使用count()的版本慢大约5%。