I am looking for the most pythonic way of splitting a list of numbers into smaller lists based on a number missing in the sequence. For example, if the initial list was:
我正在寻找最基本的方法,根据序列中缺少的数字将数字列表拆分成较小的列表。例如,如果初始列表是:
seq1 = [1, 2, 3, 4, 6, 7, 8, 9, 10]
the function would yield:
该函数将产生:
[[1, 2, 3, 4], [6, 7, 8, 9, 10]]
or
要么
seq2 = [1, 2, 4, 5, 6, 8, 9, 10]
would result in:
会导致:
[[1, 2], [4, 5, 6], [8, 9, 10]]
4 个解决方案
#1
36
From the python documentation:
从python文档:
>>> # 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.
>>> 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):
... print map(itemgetter(1), g)
...
[1]
[4, 5, 6]
[10]
[15, 16, 17, 18]
[22]
[25, 26, 27, 28]
The groupby() function from the itertools module generates a break every time the key function changes its return value. The trick is that the return value is the number in the list minus the position of the element in the list. This difference changes when there is a gap in the numbers.
每次键函数更改其返回值时,itertools模块中的groupby()函数都会生成中断。诀窍是返回值是列表中的数字减去列表中元素的位置。当数字存在差距时,这种差异会发生变化。
The itemgetter() function is from the operator module, you'll have to import this and the itertools module for this example to work.
itemgetter()函数来自运算符模块,您必须导入此函数并使用itertools模块才能使用此示例。
Full example with your data:
完整的数据示例:
>>> from operator import itemgetter
>>> from itertools import *
>>> seq2 = [1, 2, 4, 5, 6, 8, 9, 10]
>>> list = []
>>> for k, g in groupby(enumerate(seq2), lambda (i,x):i-x):
... list.append(map(itemgetter(1), g))
...
>>> print list
[[1, 2], [4, 5, 6], [8, 9, 10]]
Or as a list comprehension:
或者作为列表理解:
>>> [map(itemgetter(1), g) for k, g in groupby(enumerate(seq2), lambda (i,x):i-x)]
[[1, 2], [4, 5, 6], [8, 9, 10]]
#2
4
Another option which doesn't need itertools etc.:
另一个不需要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]]
#3
3
This is a solution that works in Python 3 (based on previous answers that work in python 2 only).
这是一个适用于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]]
or as a list comprehension
或作为列表理解
>>> [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]]
Changes were needed because
需要改变因为
- Removal of tuple parameter unpacking PEP 3113
- 删除元组参数解包PEP 3113
- map returning an iterator instead of a list
- map返回迭代器而不是列表
#4
0
My way
我的方式
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)
Result
结果
[[1, 2, 3, 4, 5, 6, 7, 8], [10, 11, 12], [15, 16, 17, 18], [20, 21, 22]]
#1
36
From the python documentation:
从python文档:
>>> # 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.
>>> 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):
... print map(itemgetter(1), g)
...
[1]
[4, 5, 6]
[10]
[15, 16, 17, 18]
[22]
[25, 26, 27, 28]
The groupby() function from the itertools module generates a break every time the key function changes its return value. The trick is that the return value is the number in the list minus the position of the element in the list. This difference changes when there is a gap in the numbers.
每次键函数更改其返回值时,itertools模块中的groupby()函数都会生成中断。诀窍是返回值是列表中的数字减去列表中元素的位置。当数字存在差距时,这种差异会发生变化。
The itemgetter() function is from the operator module, you'll have to import this and the itertools module for this example to work.
itemgetter()函数来自运算符模块,您必须导入此函数并使用itertools模块才能使用此示例。
Full example with your data:
完整的数据示例:
>>> from operator import itemgetter
>>> from itertools import *
>>> seq2 = [1, 2, 4, 5, 6, 8, 9, 10]
>>> list = []
>>> for k, g in groupby(enumerate(seq2), lambda (i,x):i-x):
... list.append(map(itemgetter(1), g))
...
>>> print list
[[1, 2], [4, 5, 6], [8, 9, 10]]
Or as a list comprehension:
或者作为列表理解:
>>> [map(itemgetter(1), g) for k, g in groupby(enumerate(seq2), lambda (i,x):i-x)]
[[1, 2], [4, 5, 6], [8, 9, 10]]
#2
4
Another option which doesn't need itertools etc.:
另一个不需要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]]
#3
3
This is a solution that works in Python 3 (based on previous answers that work in python 2 only).
这是一个适用于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]]
or as a list comprehension
或作为列表理解
>>> [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]]
Changes were needed because
需要改变因为
- Removal of tuple parameter unpacking PEP 3113
- 删除元组参数解包PEP 3113
- map returning an iterator instead of a list
- map返回迭代器而不是列表
#4
0
My way
我的方式
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)
Result
结果
[[1, 2, 3, 4, 5, 6, 7, 8], [10, 11, 12], [15, 16, 17, 18], [20, 21, 22]]