小智 36
使用itertools.groupby()生成简洁但棘手的实现:
import itertools
def ranges(i):
for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
b = list(b)
yield b[0][1], b[-1][1]
print(list(ranges([0, 1, 2, 3, 4, 7, 8, 9, 11])))
Run Code Online (Sandbox Code Playgroud)
输出:
[(0, 4), (7, 9), (11, 11)]
Run Code Online (Sandbox Code Playgroud)
Fré*_*idi 10
您可以将列表推导与生成器表达式以及enumerate()和itertools.groupby()的组合一起使用:
>>> import itertools
>>> l = [0, 1, 2, 3, 4, 7, 8, 9, 11]
>>> [[t[0][1], t[-1][1]] for t in
... (tuple(g[1]) for g in itertools.groupby(enumerate(l), lambda (i, x): i - x))]
[[0, 4], [7, 9], [11, 11]]
Run Code Online (Sandbox Code Playgroud)
首先,enumerate()将从列表项及其各自的索引构建元组:
>>> [t for t in enumerate(l)]
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 7), (6, 8), (7, 9), (8, 11)]
Run Code Online (Sandbox Code Playgroud)
然后groupby()将使用它们的索引和它们的值之间的差异对这些元组进行分组(对于连续值将是相等的):
>>> [tuple(g[1]) for g in itertools.groupby(enumerate(l), lambda (i, x): i - x)]
[((0, 0), (1, 1), (2, 2), (3, 3), (4, 4)), ((5, 7), (6, 8), (7, 9)), ((8, 11),)]
Run Code Online (Sandbox Code Playgroud)
从那里,我们只需要根据每个组的第一个和最后一个元组的值来构建列表(如果组只包含一个项目,那么它们将是相同的).
您还可以使用[(t[0][1], t[-1][1]) ...]构建范围元组列表而不是嵌套列表,甚至((t[0][1], t[-1][1]) ...)可以将整个表达式转换为generator可以在运行中懒惰地构建范围元组的迭代.
这是对非常优雅的@juanchopanza答案的改进.这个包含非唯一和非排序的输入,也兼容python3:
import itertools
def to_ranges(iterable):
iterable = sorted(set(iterable))
for key, group in itertools.groupby(enumerate(iterable),
lambda t: t[1] - t[0]):
group = list(group)
yield group[0][1], group[-1][1]
Run Code Online (Sandbox Code Playgroud)
例:
>>> x
[44, 45, 2, 56, 23, 11, 3, 4, 7, 9, 1, 2, 2, 11, 12, 13, 45]
>>> print( list(to_ranges(x)))
[(1, 4), (7, 7), (9, 9), (11, 13), (23, 23), (44, 45), (56, 56)]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
17231 次 |
| 最近记录: |