使用 itertools
这里是一个使用itertools.groupby
来检测峰值的简短解决方案。识别峰值的组被拆分,以产生实际序列。
from itertools import groupby, islice
l = [1, 2, 1, 2, 2, 0, 0]
fst, mid, nxt = groupby(l), islice(groupby(l), 1, None), islice(groupby(l), 2, None)
peaks = [[f[0], *m[1], n[0]] for f, m, n in zip(fst, mid, nxt) if f[0] < m[0] > n[0]]
print(peaks)
输出
[[1, 2, 1], [1, 2, 2, 0]]
使用循环(更快)
上面的解决方案很优雅,但由于创建了三个groupby
的实例,所以需要遍历列表三次。
下面是一种使用单次遍历的解决方案。
def peaks(lst):
first = 0
last = 1
while last < len(lst) - 1:
if lst[first] < lst[last] == lst[last+1]:
last += 1
elif lst[first] < lst[last] > lst[last+1]:
yield lst[first:last+2]
first = last + 1
last += 2
else:
first = last
last += 1
l = [1, 2, 1, 2, 2, 0, 0]
print(list(peaks(l)))
输出
[[1, 2, 1], [1, 2, 2, 0]]
关于基准测试的注释
在使用timeit
进行基准测试后,我发现使用循环的解决方案的性能提高了约20%。对于短列表,groupby
的开销可能会将该数字提高到40%。此基准测试是在Python 3.6上完成的。