Петли не всегда плохие (особенно когда они вам нужны). Кроме того, нет инструмента или алгоритма, который сделает это быстрее, чем O (n). Итак, давайте просто сделаем хорошую петлю.
Функция генератора
def cumsum_breach(x, target):
total = 0
for i, y in enumerate(x):
total += y
if total >= target:
yield i
total = 0
list(cumsum_breach(x, 10))
[4, 9]
Just In Time компилируется с Numba
Numba - это сторонняя библиотека, которую необходимо установить.
Numba может быть привередливым в том, какие функции поддерживаются. Но это работает.
Кроме того, как отмечает Дивакар, Numba лучше работает с массивами
from numba import njit
@njit
def cumsum_breach_numba(x, target):
total = 0
result = []
for i, y in enumerate(x):
total += y
if total >= target:
result.append(i)
total = 0
return result
cumsum_breach_numba(x, 10)
Проверка двух
Потому что мне так хотелось ¯\_(ツ)_/¯
Настройка
np.random.seed([3, 1415])
x0 = np.random.randint(100, size=1_000_000)
x1 = x0.tolist()
Точность
i0 = cumsum_breach_numba(x0, 200_000)
i1 = list(cumsum_breach(x1, 200_000))
assert i0 == i1
Время
%timeit cumsum_breach_numba(x0, 200_000)
%timeit list(cumsum_breach(x1, 200_000))
582 µs ± 40.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
64.3 ms ± 5.66 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Нумба была на порядок в 100 раз быстрее.
Для проверки подлинности яблок на яблоки я преобразую список в массив Numpy
%timeit cumsum_breach_numba(np.array(x1), 200_000)
%timeit list(cumsum_breach(x1, 200_000))
43.1 ms ± 202 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
62.8 ms ± 327 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Что приводит их примерно к равному.