您可以使用enumerate 并在生成器表达式和next 中列出切片:
out = next((p[i:] for i, item in enumerate(p) if item > 18), [])
输出:
[20, 13, 29, 3, 39]
就运行时间而言,取决于数据结构。
下图显示了p 不同长度的答案之间的运行时间差异。
如果原始数据是一个列表,那么使用 @Kelly Bundy 提出的惰性迭代器显然是赢家:
但是如果初始数据是一个 ndarray 对象,那么 @richardec 和 @0x263A (对于大型数组)提出的向量化操作会更快。特别是,无论数组大小如何,numpy 都会击败列表方法。但是对于非常大的数组,pandas 开始比 numpy 表现更好(我不知道为什么,如果有人能解释一下,我(我相信其他人)会很感激)。
用于生成第一个图的代码:
import perfplot
import numpy as np
import pandas as pd
import random
from itertools import dropwhile
def it_dropwhile(p):
return list(dropwhile(lambda x: x <= 18, p))
def walrus(p):
exceeded = False
return [x for x in p if (exceeded := exceeded or x > 18)]
def explicit_loop(p):
for i, x in enumerate(p):
if x > 18:
output = p[i:]
break
else:
output = []
return output
def genexpr_next(p):
return next((p[i:] for i, item in enumerate(p) if item > 18), [])
def np_argmax(p):
return p[(np.array(p) > 18).argmax():]
def pd_idxmax(p):
s = pd.Series(p)
return s[s.gt(18).idxmax():]
def list_index(p):
for x in p:
if x > 18:
return p[p.index(x):]
return []
def lazy_iter(p):
it = iter(p)
for x in it:
if x > 18:
return [x, *it]
return []
perfplot.show(
setup=lambda n: random.choices(range(0, 15), k=10*n) + random.choices(range(-20,30), k=10*n),
kernels=[it_dropwhile, walrus, explicit_loop, genexpr_next, np_argmax, pd_idxmax, list_index, lazy_iter],
labels=['it_dropwhile','walrus','explicit_loop','genexpr_next','np_argmax','pd_idxmax', 'list_index', 'lazy_iter'],
n_range=[2 ** k for k in range(18)],
equality_check=np.allclose,
xlabel='~n/20'
)
用于生成第二个图的代码(注意我必须修改list_index,因为numpy 没有index 方法):
def list_index(p):
for x in p:
if x > 18:
return p[np.where(p==x)[0][0]:]
return []
perfplot.show(
setup=lambda n: np.hstack([np.random.randint(0,15,10*n), np.random.randint(-20,30,10*n)]),
kernels=[it_dropwhile, walrus, explicit_loop, genexpr_next, np_argmax, pd_idxmax, list_index, lazy_iter],
labels=['it_dropwhile','walrus','explicit_loop','genexpr_next','np_argmax','pd_idxmax', 'list_index', 'lazy_iter'],
n_range=[2 ** k for k in range(18)],
equality_check=np.allclose,
xlabel='~n/20'
)