在python中将整数列表转换为范围

Akh*_*hil 31 python integer list range

python中是否存在可以将增加的整数列表转换为范围列表的内容

例如,给定{0,1,2,3,4,7,8,9,11}我想得到{{0,4},{7,9},{11,11}}.

我可以写一个程序来做这个,但想知道python中是否有内置函数

小智 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)

  • 这真的很有用,我想知道你是否可以解释这个方法是如何工作的,所以我可以理解它的功能.如果可能的话,这将是伟大的. (2认同)
  • 这个配方也可以在“more_itertools.consecutive_groups”中找到。请参阅[此处](/sf/answers/3334985531/)的演示。 (2认同)

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可以在运行中懒惰地构建范围元组的迭代.

  • lambda 参数解包在哪些 Python 版本中起作用?`python3.9 -c 'fn1 =amba(a, b): a + b'` `SyntaxError: invalid syntax` --- 我认为它只出现在过时的 Python 2 中。参见 https://stackoverflow.com/ questions/21892989/what-is-the-good-python3-equivalent-for-auto-tuple-unpacking-in-lambda --- 好的,我找到了这个的 PEP:https://www.python.org/ dev/peps/pep-3113/ --- 恕我直言,答案应该是固定的。 (2认同)

luc*_*uca 6

这是对非常优雅的@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)