2009-02-28 36 views
50

Załóżmy, że tworzę prostą klasę, która działa podobnie do struktury w stylu C, aby po prostu przechowywać elementy danych. Próbuję dowiedzieć się, jak przeszukiwać listę obiektów dla obiektów z atrybutem równym określonej wartości. Poniżej znajduje się trywialny przykład ilustrujący to, co próbuję zrobić.Wyszukiwanie listy obiektów w Pythonie

Na przykład:

class Data: 
    pass 

myList = [] 

for i in range(20): 
    data = Data() 
    data.n = i 
    data.n_squared = i * i 
    myList.append(data) 

Jak bym go o przeszukiwaniu listy mylist celu ustalenia, czy zawiera ona element z n == 5?

Byłem Googling i przeszukiwania dokumentacji Pythona, i myślę, że może być w stanie to zrobić ze zrozumieniem listy, ale nie jestem pewien. Dodam jeszcze, że muszę przy okazji używać Pythona 2.4.3, więc żadne nowe funkcje 2.6 lub 3.x gee-whiz nie są dla mnie dostępne.

+0

Może niezamierzony cokół swojej np mojaLista = [danych (n) == 0, danych(), n = 1,.. , ...] gdzie data.n zostanie przypisana przez range(), a data.n będzie indeksem do myList. W związku z tym pozwala wyciągnąć wszelkie wystąpienie Data() po prostu przez odniesienie myList przez wartość indeksu. Oczywiście możesz później zmodyfikować myList [0] .n = 5.2 lub coś podobnego. A przykład był prawdopodobnie zbyt uproszczony. – DevPlayer

Odpowiedz

66

Można uzyskać listę wszystkich elementy pasujące listę zrozumieniem:

[x for x in myList if x.n == 30] # list of all elements with .n==30 

Jeśli po prostu chcesz sprawdzić, czy lista zawiera element którykolwiek z elementów, który pasuje i wykonuje (względnie) efektywnie, możesz wykonać

def contains(list, filter): 
    for x in list: 
     if filter(x): 
      return True 
    return False 

if contains(myList, lambda x: x.n == 3) # True if any element has .n==3 
    # do stuff 
+19

lub dowolny (custom_filter (x) dla x w myList, jeśli x.n == 30), który jest po prostu funkcją "zawiera" jako wbudowany. – nosklo

+0

Błąd składni na nosklo - potrzebujesz dodatkowego zestawu() wokół generatora. – gahooa

+0

Nie tak. Spróbuj i zobacz. –

1

Należy dodać __eq__ oraz sposobu __hash__ do klasy Data, to może sprawdzić, czy atrybuty __dict__ są równe (same właściwości), a następnie, gdy ich wartości są równe, too.

Jeśli tak, że można użyć

test = Data() 
test.n = 5 

found = test in myList 

The in kontrole słów kluczowych jeśli test jest w myList.

Jeśli chcesz tylko aa n nieruchomości w Data można użyć:

class Data(object): 
    __slots__ = ['n'] 
    def __init__(self, n): 
     self.n = n 
    def __eq__(self, other): 
     if not isinstance(other, Data): 
      return False 
     if self.n != other.n: 
      return False 
     return True 
    def __hash__(self): 
     return self.n 

    myList = [ Data(1), Data(2), Data(3) ] 
    Data(2) in myList #==> True 
    Data(5) in myList #==> False 
25
[x for x in myList if x.n == 30]    # list of all matches 
any(x.n == 30 for x in myList)     # if there is any matches 
[i for i,x in enumerate(myList) if x.n == 30] # indices of all matches 

def first(iterable, default=None): 
    for item in iterable: 
    return item 
    return default 

first(x for x in myList if x.n == 30)   # the first match, if any 
+0

Jest to dobra odpowiedź z powodu "pierwszej" metody, która jest prawdopodobnie najczęstszym przypadkiem użycia. – galarant

36

Tylko dla kompletności, nie zapominajmy najprostszą rzeczą, która mogłaby działać:

for i in list: 
    if i.n == 5: 
    # do something with it 
    print "YAY! Found one!" 
24
filter(lambda x: x.n == 5, myList) 
+23

dla kogoś, kto chce się nauczyć Pythona, zrozumienie lambda jest proste. – vartec

+1

Cóż, tak i nie - ze zrozumieniem listy i sortowaniem kluczowych funkcji takich jak operator.attrgetter, rzadko używam 'lambda's. –

7

Można użyć in szukać pozycji w kolekcji, a listuj zrozumienie, aby wyodrębnić interesujące Cię pole. To (działa dla list, zestawów, krotek i wszystkiego, co definiuje __contains__ lub __getitem__).

if 5 in [data.n for data in myList]: 
    print "Found it" 

Zobacz także:

46

prosty, elegancki i potężny:

Wyrażenie generator w połączeniu z wbudowanego polecenia ... (pyt hon 2.5+)

any(x for x in mylist if x.n == 10) 

Używa Python any() polecenie wbudowane, które jest zdefiniowane następująco:

any (iterable)-> zwróci TRUE jeśli element iterowalny jest prawdą. Odpowiednik:

def any(iterable): 
    for element in iterable: 
     if element: 
      return True 
    return False 
+0

Nice. FYI możesz zrobić dowolne (x na x w mylist, jeśli x.n == 10), aby zapisać niektóre parens (także == not =). –

3

rozważyć użycie Dictionary

myDict = {} 

for i in range(20): 
    myDict[i] = i * i 

print(5 in myDict) 
+0

Lub: d = dict ((i, i * i) dla mnie w zakresie (20)) – hughdbrown

+0

Rozwiązuje to banalny problem, którego użyłem do zilustrowania mojego pytania, ale tak naprawdę nie rozwiązał mojego pytania root. Odpowiedź, której szukałem (ponad 5 lat temu), to zrozumienie listy. :) – m0j0