2011-08-19 125 views
92

我有對象的列表。我想在此列表中找到一個具有屬性(或方法結果 - 無論)的對象(等於value)。查找對象具有屬性等於某個值(滿足任何條件)

什麼是找到它的最佳方式?

這裏的測試用例:

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()將沒有任何區別,因爲它仍然會通過列表迭代。

PS:公式來value僅僅是一個例子。當然,我們想獲得滿足任何條件的元素。

+2

下面是這個問題的一個很好的討論:http://tomayko.com/writings/cleanest-python-find -in-list-function –

+0

原文是__ridiculously__過期,但第二個回覆完全匹配我的單行版本。雖然我不確定它比基本循環版本更好。 – agf

回答

199
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 

天真環路斷路版本,是完全符合Python - 它的簡潔,清晰,高效。爲了使之成爲一個班輪的行爲一致:

for x in test_list: 
    if x.value == value: 
     print "i found it!" 
     break 
else: 
    x = None 

如果你不break圈外這將分配給Nonex

+21

+1令人放心的「The naive loop-break版本,完全是Pythonic」。 – LaundroMat

+0

偉大的解決方案,但我如何修改您的行,以便我可以使x.value實際上意味着x.fieldMemberName該名稱存儲在值中? 場= 「名稱」 下一個(在test_list(X爲x如果x.field ==值),無) 所以在這種情況下,我其實覈對x.name,不x.field –

+2

@StewartDale這並不完全清楚你在問什麼,但我認爲你的意思是......如果getattr(x,x.fieldMemberName)==值。這將從'x'中獲取存儲在'fieldMemberName'中的名稱的屬性,並將其與'value'進行比較。 – agf

1

我只是碰到了類似的問題,並制定了對列表中沒有對象符合要求的情況下小的優化(對我的使用情況,這導致重大的性能提升)。

隨着list test_list,我保留了一個額外的設置test_value_set,它由我需要過濾的列表的值組成。所以這裏agf解決方案的其他部分變得非常快。

4

因爲它沒有被提及剛剛完成。 好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 
+0

我很喜歡這種風格,但有兩個潛在的問題。 ** 1 **:僅適用於Python 3;在Python 2中,'filter'返回一個與'next'不兼容的列表。 ** 2 **:它要求有一個明確的匹配,否則你會得到一個'StopIteration'異常。 – freethebees

+0

1:我不知道Python 2.當我開始使用Python時,Python 3已經可用。不幸的是,我對Python 2的特定方面一無所知。2. @freethebees正如agf指出的那樣。如果你不喜歡異常,你可以使用next(...,None)或其他默認值。我還將它添加爲我的代碼的評論。 – Nimi

+0

我已更新答案以反映評論。 – Nimi

相關問題