根据序列中缺失的数字拆分列表

问题描述 投票:0回答:6

我正在寻找最Pythonic的方法,根据序列中缺少的数字将数字列表分割成更小的列表。例如,如果初始列表是:

seq1 = [1, 2, 3, 4, 6, 7, 8, 9, 10]

该函数将产生:

[[1, 2, 3, 4], [6, 7, 8, 9, 10]]

seq2 = [1, 2, 4, 5, 6, 8, 9, 10]

会导致:

[[1, 2], [4, 5, 6], [8, 9, 10]]
python list sequence
6个回答
54
投票

Python 文档中的代码的 Python 3 版本

>>> # Find runs of consecutive numbers using groupby.  The key to the solution
>>> # is differencing with a range so that consecutive numbers all appear in
>>> # same group.
>>> from itertools import groupby
>>> from operator import itemgetter
>>> data = [ 1,  4,5,6, 10, 15,16,17,18, 22, 25,26,27,28]
>>> for k, g in groupby(enumerate(data), lambda i_x: i_x[0] - i_x[1]):
...     print(list(map(itemgetter(1), g)))
...
[1]
[4, 5, 6]
[10]
[15, 16, 17, 18]
[22]
[25, 26, 27, 28]

每次关键函数更改其返回值时,itertools 模块中的

groupby
函数都会生成一个中断。技巧在于返回值是列表中的数字减去列表中元素的位置。当数字存在差距时,这种差异就会发生变化。

itemgetter
函数来自operator模块,您必须导入它和itertools模块才能使本示例工作。

或者,作为列表理解:

>>> [map(itemgetter(1), g) for k, g in groupby(enumerate(seq2), lambda i_x: i_x[0] - i_x[1])]
[[1, 2], [4, 5, 6], [8, 9, 10]]

9
投票

这是一个适用于 Python 3 的解决方案(基于之前仅适用于 Python 2 的答案)。

>>> from operator import itemgetter
>>> from itertools import *
>>> groups = []
>>> for k, g in groupby(enumerate(seq2), lambda x: x[0]-x[1]):
>>>     groups.append(list(map(itemgetter(1), g)))
... 
>>> print(groups)
[[1, 2], [4, 5, 6], [8, 9, 10]]

或作为列表理解

>>> [list(map(itemgetter(1), g)) for k, g in groupby(enumerate(seq2), lambda x: x[0]-x[1])]
[[1, 2], [4, 5, 6], [8, 9, 10]]

需要做出改变,因为

  • 删除元组参数拆包PEP 3113
  • map 返回迭代器而不是列表

6
投票

另一个不需要 itertools 等的选项:

>>> data = [1, 4, 5, 6, 10, 15, 16, 17, 18, 22, 25, 26, 27, 28]
>>> spl = [0]+[i for i in range(1,len(data)) if data[i]-data[i-1]>1]+[None]
>>> [data[b:e] for (b, e) in [(spl[i-1],spl[i]) for i in range(1,len(spl))]]
... [[1], [4, 5, 6], [10], [15, 16, 17, 18], [22], [25, 26, 27, 28]]

1
投票

我的路

alist = [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 15, 16, 17, 18, 20, 21, 22]
newlist = []
start = 0
end = 0
for index,value in enumerate(alist):
    if index < len(alist)-1:
        if alist[index+1]> value+1:
            end = index +1
            newlist.append(alist[start:end])
            start = end
    else:
            newlist.append(alist[start: len(alist)])
print(newlist)

结果

[[1, 2, 3, 4, 5, 6, 7, 8], [10, 11, 12], [15, 16, 17, 18], [20, 21, 22]]

1
投票

我更喜欢这个,因为它不需要任何额外的库或对第一种情况进行特殊处理:

a = [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 15, 16, 17, 18, 20, 21, 22]
b = []
subList = []
prev_n = -1

for n in a:
    if prev_n+1 != n:            # end of previous subList and beginning of next
        if subList:              # if subList already has elements
            b.append(subList)
            subList = []
    subList.append(n)
    prev_n = n

if subList:
    b.append(subList)

print a
print b

输出:

[1,2,3,4,5,6,7,8,10,11,12,15,16,17,18,20,21,22]

[[1,2,3,4,5,6,7,8],[10,11,12],[15,16,17,18],[20,21,22]]


0
投票

使用 numpy 进行简短的单行代码:

seq2 = [1, 2, 4, 5, 6, 8, 9, 10]
np.split(seq2, np.where(np.diff(seq2) > 1)[0] + 1)

结果:

[array([1, 2]), array([4, 5, 6]), array([ 8,  9, 10])]
© www.soinside.com 2019 - 2024. All rights reserved.