xより大きい最初のPythonリストインデックス?


81

xより大きいリストの最初のインデックスを見つけるための最もPython的な方法は何でしょうか?

たとえば、

list = [0.5, 0.3, 0.9, 0.8]

関数

f(list, 0.7)

戻るだろう

2.

57
...変数名として「リスト」を使用していない
mshsayem

11
あなたは「pythonic」を意味します。urbandictionary.com/define.php?term=Pythonesqueによると、「pythonesque」は「シュールでばかげた」を意味し、それがあなたが探しているものではないと思います:P
Roberto Bonvallet 2010

1
質問はあいまいです。答えは理由ですか20.9 > 0.7それとも理由0.8 > 0.7ですか?つまり、順番に検索するのですか、それとも値が大きい順に検索するのですか?
Sergey Orshanskiy 2015年


新しい質問の方が一般的であるため、この質問を重複として閉じることに投票しました。その逆も同様です。
クリスチャンCiupitu

回答:


118
next(x[0] for x in enumerate(L) if x[1] > 0.7)

29
+1:魔法数は避けたいのですが:next(idx for idx、value in enumerate(L)if value> 0.7)
truppo 2010

38
1簡略化のためとnext()、多分この読みやすさのために:next(i for i,v in enumerate(L) if v > 0.7)
ウィル・ハーディ

14
これは見栄えが良いですが、結果が得られない場合は、混乱を招くStopIterationが発生します。
Virgil Dupras 2010

3
@Wim:しかし、その後、シーケンス全体の評価に戻ります。itertools.chain()このようなリストを追加する代わりに使用してください。
Ignacio Vazquez-Abrams

3
@Wimここではchain()は必要ありません。next()は2番目の引数を受け入れます:next((i for i, x in enumerate(L) if x > value), -1)
jfs 2018年

35

リストがソートされている場合bisect.bisect_left(alist, value)、大きなリストの方がnext(i for i, x in enumerate(alist) if x >= value)。よりも高速です。


良い答え-小さな4要素のソート済みリストを使用した場合は間違いなく5〜6倍高速でしたが、(エラーが発生しているかどうかはわかりません)、10000要素のnumpy配列の長いリストを使用してtimeitを使用してこれを計測するとしかし、上記のリスト内包表記の回答の約2倍遅いことがわかりましたが、これには驚きました。
エイドリアントンプキンス

1
@AdrianTompkins:ベンチマークに問題があります。bisect_leftはO(log n)ですが、listcompはO(n)です。つまり、が大きいほどnbisect_left()側の利点が大きくなります。私はのインデックスを見つけることを試みてきた500_000中でrange(10**6)使用したbisect_left()3.75マイクロ秒>とでgenexprを使用して- next()[> 51.0ミリ-10_000回]遅く予想通り。
JFS

16
filter(lambda x: x>.7, seq)[0]

4
-1:技術的には正しいですが、リスト内包表記が読みやすく、パフォーマンスが高いフィルターは使用しないでください
truppo 2010

filter(lambda x:x [1]> .7、enumerate(seq))[0] [0]-単純な線形検索
ローテク2013年

4
Python 3の@truppoフィルターはジェネレーターを返すので、リスト内包表記より悪くないはずですか?また、この方法は、ソリューションを列挙するよりも読みやすいと思います。
BubuIIC 2013年

これについて良くないことの1つは、.7より大きいアイテムがseqにない場合、例外処理に入るということです。
ブライアン

解決策は技術的に正しくありません。質問の作成者は、リスト内の要素のインデックスを見つける方法を尋ねました。ただし、このソリューションは代わりにレコードを返します。Eventmoreは、Python 3.8で、それはそれより遅くですbisect_left()(最速)とenumerate()
SergeyNevmerzhitsky20年

16
>>> alist= [0.5, 0.3, 0.9, 0.8]
>>> [ n for n,i in enumerate(alist) if i>0.7 ][0]
2

2
'x'がリスト内の他の値よりも大きい場合は失敗します
mshsayem 2010

2
@mshsayem:この場合の問題は明確に定義されていません。失敗は正しいことかもしれません。
S.Lott 2010

@ S.Loot:良い点です。リストにない場合に失敗すると、これを変数に割り当てるときに理解できるエラーが発生しますIndexError: list index out of rangeindex = next[ n for n,i in enumerate(alist) if i>0.7 ]エラーを使用すると、次のようになりNameError: name 'index' is not definedます。nextわずかに高速です。タイミングの差は12.7nsですが、60000の数値では11.9nsです。
レオ



3

1)NUMPY ARGWHERE、一般リスト

numpyを使用しても問題がない場合は、一般的なリスト(ソート済みまたはソートなし)で以下が機能します。

numpy.argwhere(np.array(searchlist)>x)[0]

または、リストとして回答が必要な場合:

numpy.argwhere(np.array(searchlist)>x).tolist()[0]

または、整数インデックスとしての回答が必要な場合:

numpy.argwhere(np.array(searchlist)>x).tolist()[0][0]

2)NUMPY SEARCHSORTED、ソート済みリスト(リストの検索に非常に効率的)

ただし、検索リストが並べ替えられている場合は、関数np.searchsortedを使用する方がはるかにクリーンで優れています。

numpy.searchsorted(searchlist,x)

この関数を使用することの良い点は、単一の値xを検索するだけでなく、xもリストにすることができることです。つまり、検索された値のリストのインデックスのリストを返すこともできます[x1、x2、x3 .. xn ]、(そしてこの場合、リスト内包に比べて非常に効率的です)。


2

私のリストが非常に長いとき、私は同様の問題を抱えていました。理解またはフィルターベースのソリューションは、リスト全体を通過します。itertools.takewhileは、条件が最初にfalseになると、ループを中断します。

from itertools import takewhile

def f(l, b): return len([x for x in takewhile(lambda x: x[1] <= b, enumerate(l))])

l = [0.5, 0.3, 0.9, 0.8]
f(l, 0.7)

1
def f(l、b)を記述しない理由:return len(list(takewhile(lambda x:x [1] <= b、enumerate(l))))?
AvoAsatryan19年

2

すでにたくさんの答えがあることは知っていますが、pythonicという単語が「ワンライナー」に翻訳されていると感じることがあります。

より良い定義がこの答えに近いと思うとき:

「Python言語の機能を活用して、明確で簡潔で保守しやすいコードを作成します。」

上記の回答のいくつかは簡潔ですが、明確ではないと思います。初心者のプログラマーが理解するには時間がかかるため、多くのスキルレベルで構築されたチームにとって非常に保守しやすくなりません。

l = [0.5, 0.3, 0.9, 0.8]

def f(l, x):
    for i in l:
        if i >x: break
    return l.index(i)


f(l,.7)

または

l = [0.5, 0.3, 0.9, 0.8]

def f(l, x):
    for i in l:
        if i >x: return l.index(i)



f(l,.7)

上記は初心者には簡単に理解でき、ベテランのPythonプログラマーにも受け入れられるほど簡潔だと思います。

ばかげたコードを書くことは良いことだと思います。


1
>>> f=lambda seq, m: [ii for ii in xrange(0, len(seq)) if seq[ii] > m][0]
>>> f([.5, .3, .9, .8], 0.7)
2

それはかなり滑らかに見えます。しかし、理論的には、リスト全体をトラバースしてから、最初の結果(xより大きい)を返しますよね?最初の結果を見つけた直後に停止するものを作成する方法はありますか?
c00kiemonster 2010

リスト全体をトラバースすることの何が問題になっていますか?0.7より大きい最初の値がリストの終わり近くにある場合、違いはありません。
ghostdog74 2010

3
本当。しかし、この特定のケースでは、関数を使用する予定のリストがかなり長いので、一致するものが見つかったらすぐにトラバースを終了することをお
勧めし

長いかどうかに関係なく、最初の値がリストの最後の2番目の項目である場合でも、そこに到達するにはリスト全体をトラバースする必要があります。
ghostdog74 2010

4
@ ghostdog74:はい、しかしこれはすべてのケースを最悪のケースにしたい理由ではありません。
UncleBens 2010


-1

これを試してください:

def Renumerate(l):
    return [(len(l) - x, y) for x,y in enumerate(l)]

サンプルコード:

Renumerate(range(10))

出力:

(10, 0)
(9, 1)
(8, 2)
(7, 3)
(6, 4)
(5, 5)
(4, 6)
(3, 7)
(2, 8)
(1, 9)

1
問題は、「リスト内でxより大きい最初のインデックスを見つけることでした。
ジーノメンピン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.