オブジェクトのリストがあります。このリストで、value
に等しい属性(またはメソッドの結果-何でも)を持つ1つの(最初のまたは何でも)オブジェクトを見つけたいです。
それを見つける最良の方法は何ですか?
テストケースは次のとおりです。
class Test:
def __init__(self, value):
self.value = value
import random
value = 5
test_list = [Test(random.randint(0,100)) for x in range(1000)]
# that I would do in Pascal, I don't believe isn't anywhere near 'Pythonic'
for x in test_list:
if x.value == value:
print "i found it!"
break
ジェネレーターとreduce()
を使用しても、リストを繰り返し処理するため、違いは生じないと思います。
追伸:value
の方程式は単なる例です。もちろん、任意の条件を満たす要素を取得したいです。
next((x for x in test_list if x.value == value), None)
これは、条件に一致するリストから最初のアイテムを取得し、一致するアイテムがない場合はNone
を返します。それは私の好みの単一表現形式です。
しかしながら、
for x in test_list:
if x.value == value:
print "i found it!"
break
素朴なループブレイクバージョンは完全にPythonicです-簡潔で、明確で、効率的です。ワンライナーの動作と一致させるには:
for x in test_list:
if x.value == value:
print "i found it!"
break
else:
x = None
これにより、None
をループ外にしない場合、x
がbreak
に割り当てられます。
完了のためだけに言及されていないので。フィルタリングする要素をフィルタリングするための優れたol 'フィルター.
関数型プログラミングftw。
####### Set Up #######
class X:
def __init__(self, val):
self.val = val
elem = 5
my_unfiltered_list = [X(1), X(2), X(3), X(4), X(5), X(5), X(6)]
####### Set Up #######
### Filter one liner ### filter(lambda x: condition(x), some_list)
my_filter_iter = filter(lambda x: x.val == elem, my_unfiltered_list)
### Returns a flippin' iterator at least in Python 3.5 and that's what I'm on
print(next(my_filter_iter).val)
print(next(my_filter_iter).val)
print(next(my_filter_iter).val)
### [1, 2, 3, 4, 5, 5, 6] Will Return: ###
# 5
# 5
# Traceback (most recent call last):
# File "C:\Users\mousavin\workspace\Scripts\test.py", line 22, in <module>
# print(next(my_filter_iter).value)
# StopIteration
# You can do that None stuff or whatever at this point, if you don't like exceptions.
一般的に、pythonリストの内包表記が優先されること、または少なくともそれが私が読んだものであることは知っていますが、この問題が正直であるとは思いません。もちろんPythonはFP言語ではありませんが、Map/Reduce/Filterは完全に読みやすく、関数型プログラミングの標準的なユースケースの最も標準的なものです。
それであなたは行きます。あなたの関数型プログラミングを知ってください。
フィルター条件リスト
これより簡単になることはありません。
next(filter(lambda x: x.val == value, my_unfiltered_list)) # Optionally: next(..., None) or some other default value to prevent Exceptions
私はちょうど同様の問題に遭遇し、リスト内のオブジェクトが要件を満たしていない場合の小さな最適化を考案しました(私のユースケースでは、これにより大きなパフォーマンスの改善がもたらされました):
リストtest_listとともに、追加のセットtest_value_setを保持します。このセットは、フィルタリングする必要があるリストの値で構成されています。そのため、agfのソリューションのelse部分は非常に高速になります。
Test
クラスに __eq__
メソッドを使用してリッチ比較を実装し、in
演算子を使用することもできます。これが最善のスタンドアロンの方法であるかどうかはわかりませんが、Test
に基づいてvalue
インスタンスを他のどこかで比較する必要がある場合、これは便利です。
class Test:
def __init__(self, value):
self.value = value
def __eq__(self, other):
"""To implement 'in' operator"""
# Comparing with int (assuming "value" is int)
if isinstance(other, int):
return self.value == other
# Comparing with another Test object
Elif isinstance(other, Test):
return self.value == other.value
import random
value = 5
test_list = [Test(random.randint(0,100)) for x in range(1000)]
if value in test_list:
print "i found it"
以下のコードでは、xGenは匿名ジェネレーター式であり、yFiltはフィルターオブジェクトです。 xGenの場合、リストを使い果たしたときにStopIterationをスローするのではなく、追加のNoneパラメーターが返されることに注意してください。
arr =((10,0), (11,1), (12,2), (13,2), (14,3))
value = 2
xGen = (x for x in arr if x[1] == value)
yFilt = filter(lambda x: x[1] == value, arr)
print(type(xGen))
print(type(yFilt))
for i in range(1,4):
print('xGen: pass=',i,' result=',next(xGen,None))
print('yFilt: pass=',i,' result=',next(yFilt))
出力:
<class 'generator'>
<class 'filter'>
xGen: pass= 1 result= (12, 2)
yFilt: pass= 1 result= (12, 2)
xGen: pass= 2 result= (13, 2)
yFilt: pass= 2 result= (13, 2)
xGen: pass= 3 result= None
Traceback (most recent call last):
File "test.py", line 12, in <module>
print('yFilt: pass=',i,' result=',next(yFilt))
StopIteration