2012-06-01 25 views
18

讓我們假設下面的簡單對象:在python查找其成員對象列表內

class Mock: 
    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

然後我有一些像這樣的對象列表:

myList = [Mock("Dan", 34), Mock("Jack", 30), Mock("Oli", 23)...] 

有一些內置在哪裏我可以得到所有Mocks年齡爲30? 我當然可以遍歷自己過他們,並比較他們的年齡,但類似

find(myList, age=30) 

將是很好。有沒有這樣的事情?

回答

32

你可能要預先對其進行索引 -

from collections import defaultdict 

class Mock(object): 
    age_index = defaultdict(list) 

    def __init__(self, name, age): 
     self.name = name 
     self.age = age 
     Mock.age_index[age].append(self) 

    @classmethod 
    def find_by_age(cls, age): 
     return Mock.age_index[age] 

編輯:一張圖片勝過千言萬語:

enter image description here

X axis是myList中的Mocks數,Y軸是以秒爲單位的運行時間。

  • 紅點是@ dcrooney的過濾器()方法
  • 藍點是@ marshall.ward的列表理解
  • 綠點隱藏X軸的後面,是我的索引;-)
+0

非常感謝這個答案。我正要手動重新實現類似的東西。 – xlash

+2

謝謝。和好的圖。但是討論各種折衷會有幫助,例如額外的啓動時間來建立索引,以及它所需的空間。 – nealmcb

34

你可以嘗試filter()

filter(lambda x: x.age == 30, myList) 

這將返回一個列表,只有這些對象滿足lambda表達式。

+3

如果你打算通過這個屬性常常做一個查找,您可能希望維持基於該屬性的'dict'。 –

+1

至少對於Python 3.5,您需要'list(filter(lambda x:x.age == 30,myList))'來獲取列表。 – CGFoX

+1

使用'filter()'是舊的經典答案,但在其他答案中已經討論過,列表推理在各種版本的Python中更快且更具可移植性。 – nealmcb

19

列表理解可以選擇這些了:

new_list = [x for x in myList if x.age == 30] 
+0

也是不錯的解決方案,但@drooney答案適合更多的功能。有人比較什麼更快? –

+1

'timeit'爲我的機器提供了大約0.30的usec用於列表理解和0.58的lambda過濾器。但是它們在本質上是等同的,所以你應該使用你喜歡的那個。 –

+2

關於這個問題的一些很好的討論,以及:http://stackoverflow.com/a/1247490/317172 –

5

名單理解幾乎總是更快的方法來做這些事情(在這裏快兩倍),但如前所述,如果您關心速度,索引更快。

~$ python -mtimeit -s"from mock import myList" "filter(lambda x: x.age==21, myList)" 
1000000 loops, best of 3: 1.34 usec per loop 
~$ python -mtimeit -s"from mock import myList" "[x for x in myList if x.age==21]" 
1000000 loops, best of 3: 0.63 usec per loop 

對於文件mock.py當前目錄:

class Mock: 
    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

myList = [Mock('Tom', 20), Mock('Dick', 21), Mock('Harry', 21), Mock('John', 22)] 
相關問題