使用 itertools 将列表拆分为递增的序列
Posted
技术标签:
【中文标题】使用 itertools 将列表拆分为递增的序列【英文标题】:Split a list into increasing sequences using itertools 【发布时间】:2017-02-14 22:06:44 【问题描述】:我有一个包含混合序列的列表,例如
[1,2,3,4,5,2,3,4,1,2]
我想知道如何使用 itertools 将列表拆分为递增序列,在递减点处切割列表。例如上面会输出
[[1, 2, 3, 4, 5], [2, 3, 4], [1, 2]]
这是通过注意到序列在 2 处减少,所以我们在那里切割第一个位,另一个减少是在那里再次切割。
另一个例子是序列
[3,2,1]
输出应该是
[[3], [2], [1]]
如果给定的序列正在增加,我们将返回相同的序列。例如
[1,2,3]
返回相同的结果。即
[[1, 2, 3]]
对于像
这样的重复列表[ 1, 2,2,2, 1, 2, 3, 3, 1,1,1, 2, 3, 4, 1, 2, 3, 4, 5, 6]
输出应该是
[[1, 2, 2, 2], [1, 2, 3, 3], [1, 1, 1, 2, 3, 4], [1, 2, 3, 4, 5, 6]]
我所做的是定义以下函数
def splitter (L):
result = []
tmp = 0
initialPoint=0
for i in range(len(L)):
if (L[i] < tmp):
tmpp = L[initialPoint:i]
result.append(tmpp)
initialPoint=i
tmp = L[i]
result.append(L[initialPoint:])
return result
该功能 100% 工作,但我需要对 itertools 做同样的事情,这样我就可以提高代码的效率。有没有办法使用 itertools 包来避免显式循环?
【问题讨论】:
这是您认为可以改进的工作代码,请考虑Code Review。 是的。代码正在运行。我在想也许 itertools 包可以帮助改进它 【参考方案1】:使用numpy
,可以使用numpy.split
,这需要索引作为分割位置;由于您想在值减小的地方拆分,您可以使用numpy.diff
计算差异并检查差异小于零的位置并使用numpy.where
检索相应的索引,问题中最后一种情况的示例:
import numpy as np
lst = [ 1, 2,2,2, 1, 2, 3, 3, 1,1,1, 2, 3, 4, 1, 2, 3, 4, 5, 6]
np.split(lst, np.where(np.diff(lst) < 0)[0] + 1)
# [array([1, 2, 2, 2]),
# array([1, 2, 3, 3]),
# array([1, 1, 1, 2, 3, 4]),
# array([1, 2, 3, 4, 5, 6])]
【讨论】:
【参考方案2】:Psidom 已经为您提供了一个很好的答案,但另一个 NumPy 解决方案是使用 scipy.signal.argrelmax
获取局部最大值,然后使用 np.split
。
from scipy.signal import argrelmax
arr = np.random.randint(1000, size=10**6)
splits = np.split(arr, argrelmax(arr)[0]+1)
【讨论】:
【参考方案3】:假设您的原始输入数组:
a = [1, 2, 3, 4, 5, 2, 3, 4, 1, 2]
首先找到应该发生分裂的地方:
p = [ i+1 for i, (x, y) in enumerate(zip(a, a[1:])) if x > y ]
然后为每个这样的拆分创建切片:
print [ a[m:n] for m, n in zip([ 0 ] + p, p + [ None ]) ]
这将打印:
[[1, 2, 3, 4, 5], [2, 3, 4], [1, 2]]
我建议使用比p
、n
、m
等更多的口语名称;-)
【讨论】:
以上是关于使用 itertools 将列表拆分为递增的序列的主要内容,如果未能解决你的问题,请参考以下文章
为啥 itertools.chain 比扁平化列表理解更快?