条件に一致するリストから最初のアイテムを取得したいと思います。結果のメソッドがリスト全体を処理しないことが重要です。これは非常に大きくなる可能性があります。たとえば、次の機能で十分です。
def first(the_iterable, condition = lambda x: True):
for i in the_iterable:
if condition(i):
return i
この関数は次のように使用できます。
>>> first(range(10))
0
>>> first(range(10), lambda i: i > 3)
4
ただし、これを実行するための優れた組み込み/ワンライナーは考えられません。必要がない場合は、特にこの関数をコピーしたくありません。条件に一致する最初のアイテムを取得する組み込みの方法はありますか?
Python 2.6以降:
一致する要素が見つからない場合にStopIteration
を発生させたい場合:
next(x for x in the_iterable if x > 3)
代わりにdefault_value
(たとえばNone
)を返したい場合:
next( (x for x in the_iterable if x>3), default_value)
この場合、ジェネレーター式の周りに追加の括弧が必要であることに注意してください-ジェネレーター式が唯一の引数ではない場合、それらは常に必要です。
ほとんどの答えは next
ビルトインを絶対に無視するので、何らかの謎の理由でPythonバージョンの問題に言及せずにバージョン2.5以前に100%焦点を当てていると思います(しかし、 doがnext
ビルトインに言及しているという回答にその言及がないので、自分で答えを提供する必要があると思ったのです-少なくとも「正しい」バージョン」の問題はこの方法で記録されます;-)。
2.5では、イテレータの .next()
メソッドは、イテレータがすぐに終了する場合、つまり、ユースケースの場合、反復可能なアイテムが条件を満たさない場合、すぐにStopIteration
を発生させます。気にしない場合(つまり、must少なくとも1つの満足できるアイテムでなければならない)、.next()
(genexpで最適、 next
ビルトインPython 2.6以降)。
あなたがdo気にするなら、Qで最初に示したように関数で物事をラップするのが最良のようであり、提案した関数の実装は問題なく、代わりにitertools
を使用することができます、さまざまな答えが示唆するように、関数の本体としてのfor...: break
ループ、genexp、またはtry/except StopIteration
。これらの選択肢のいずれにも付加価値はあまりないので、最初に提案した非常にシンプルなバージョンを選びます。
def first(iterable, condition = lambda x: True):
"""
Returns the first item in the `iterable` that
satisfies the `condition`.
If the condition is not given, returns the first item of
the iterable.
Raises `StopIteration` if no item satysfing the condition is found.
>>> first( (1,2,3), condition=lambda x: x % 2 == 0)
2
>>> first(range(3, 100))
3
>>> first( () )
Traceback (most recent call last):
...
StopIteration
"""
return next(x for x in iterable if condition(x))
ifilter
の使用と同様に、ジェネレーター式を使用できます。
>>> (x for x in xrange(10) if x > 5).next()
6
どちらの場合でも、条件を満たさない要素がない場合は、おそらくStopIteration
をキャッチする必要があります。
技術的には、次のようなことができると思います。
>>> foo = None
>>> for foo in (x for x in xrange(10) if x > 5): break
...
>>> foo
6
try/except
ブロックを作成する必要がなくなります。しかし、それは一種の曖昧で、構文を乱用しているようです。
この答え が大好きです。ただし、next()
はアイテムがないときにStopIteration
例外を発生させるため、次のスニペットを使用して例外を回避します。
a = []
item = next((x for x in a), None)
例えば、
a = []
item = next(x for x in a)
StopIteration
例外を発生させます。
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Python 3で最も効率的な方法は、次のいずれかです(同様の例を使用)。
next(i for i in range(100000000) if i == 1000)
WARNING:この式はPython 2でも機能しますが、この例では、リストではなくPython 3の反復可能オブジェクトを返すrange
が使用されますPython 2のように(Python 2でイテラブルを作成する場合は、代わりにxrange
を使用します)。
この式は、内包表記next([i for ...])
でリストを作成することを避けます。これにより、エレメントをフィルター処理する前にすべてのエレメントを含むリストが作成され、i == 1000
で繰り返しを停止するのではなく、オプション全体が処理されます。
next(filter(lambda i: i == 1000, range(100000000)))
WARNING:これはPython 2では機能しません。range
をxrange
で置き換えても、filter
はイテレータ(非効率的)の代わりにリストを作成し、next
関数のみイテレータで動作します。
他の応答で述べたように、条件が満たされないときに発生する例外を回避したい場合は、関数next
に追加のパラメーターを追加する必要があります。
next(filter(lambda i: i == 1000, range(100000000)), False)
このスタイルでは、()
を回避するために、内包表記をSyntaxError: Generator expression must be parenthesized if not sole argument
で囲む必要があります。
next((i for i in range(100000000) if i == 1000), False)
次のビルトインが存在しない古いバージョンのPythonの場合:
(x for x in range(10) if x > 3).next()
私はこれを書きます
next(x for x in xrange(10) if x > 3)
itertools
モジュールには、反復子用のフィルター関数が含まれています。フィルター処理されたイテレーターの最初の要素は、next()
を呼び出すことで取得できます。
from itertools import ifilter
print ifilter((lambda i: i > 3), range(10)).next()
を使用して
(index for index, value in enumerate(the_iterable) if condition(value))
the_iterableの最初の項目のvalueのconditionを確認できます、およびtheindexを取得し、the_iterableのすべての項目を評価する必要はありません。
使用する完全な式は
first_index = next(index for index, value in enumerate(the_iterable) if condition(value))
ここでfirst_indexは、上記の式で識別された最初の値の値を想定しています。
この質問にはすでに素晴らしい答えがあります。私は自分の問題の解決策を見つけるためにここに着陸したので、2セントを追加していますが、これはOPに非常に似ています。
ジェネレーターを使用して、条件に一致する最初のアイテムのINDEXを検索する場合は、次を実行できます。
next(index for index, value in enumerate(iterable) if condition)
組み込みのワンライナーをリクエストしているので、これはStopIteration
例外の問題を回避しますが、イテレート可能オブジェクトはリストにキャストできるように小さくする必要があります。 StopIterationを飲み込み、値をのぞかせます:
(lambda x:x[0] if x else None)(list(y for y in ITERABLE if CONDITION))
(一致する要素がない場合、None
例外ではなくStopIteration
が返されます。)
Numpyでargwhere
関数を使用することもできます。例えば:
i)「helloworld」の最初の「l」を見つけます。
import numpy as np
l = list("helloworld") # Create list
i = np.argwhere(np.array(l)=="l") # i = array([[2],[3],[8]])
index_of_first = i.min()
ii)最初の乱数> 0.1を見つける
import numpy as np
r = np.random.Rand(50) # Create random numbers
i = np.argwhere(r>0.1)
index_of_first = i.min()
iii)最後の乱数を見つける> 0.1
import numpy as np
r = np.random.Rand(50) # Create random numbers
i = np.argwhere(r>0.1)
index_of_last = i.max()