web-dev-qa-db-ja.com

Pythonでは、ソートされたリストのしきい値よりも大きい最初の値のインデックスをどのように見つけますか?

Pythonでは、ソートされたリストのしきい値よりも大きい最初の値のインデックスをどのように見つけますか?

これを行うにはいくつかの方法(線形検索、手書きの二分法など)が考えられますが、合理的に効率的なクリーンな方法を探しています。それはおそらくかなり一般的な問題なので、経験豊富なSOerが役立つと確信しています!

ありがとう!

28
static_rtti

bisect をご覧ください。

import bisect

l = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

bisect.bisect(l, 55) # returns 7

線形検索と比較してください。

timeit bisect.bisect(l, 55)
# 375ns


timeit next((i for i,n in enumerate(l) if n > 55), len(l))
# 2.24us


timeit next((l.index(n) for n in l if n > 55), len(l))
# 1.93us
47
eumiro

Itertoolsを使用した列挙/ジェネレーターアプローチよりも良い時間を得ることができます。 itertoolsは、私たち全員のパフォーマンス管理者に、基盤となるアルゴリズムのより高速な実装を提供すると思います。しかし、二分法はまだ速いかもしれません。

from itertools import islice, dropwhile

threshold = 5
seq = [1,4,6,9,11]
first_val = islice(dropwhile(lambda x: x<=threshold, seq),0,1)
result = seq.index(first_val)

イディオム/速度に関しては、ここに示されている二分法と、ドキュメントの例で質問にリストされているものとの違いについて疑問に思います。これらは値を見つけるためのアプローチを示していますが、最初の行に切り捨てられ、インデックスを返します。 「bisect」ではなく「bisect_right」と呼ばれているので、おそらく一方向からしか見えないと思います。あなたのリストがソートされていて、それ以上のものが欲しいとすれば、これは最大の検索経済かもしれません。

from bisect import bisect_right

def find_gt(a, x):
    'Find leftmost value(switching this to index) greater than x'
    return bisect_right(a, x)

興味深い質問です。

1
Profane