2010-04-01 17 views
14

Mam listę obiektów w Pythonie. Mam kolejną listę obiektów. Chcę przejrzeć pierwszą listę i sprawdzić, czy na drugiej liście znajdują się jakieś elementy.Sprawdzanie Pythona, czy obiekt znajduje się na liście obiektów

Myślałem, że mogę po prostu zrobić

for item1 in list1: 
    for item2 in list2: 
     if item1 == item2: 
      print "item %s in both lists" 

Jednak to nie wydają się działać. Chociaż jeśli to zrobię:

if item1.title == item2.title: 

działa poprawnie. Mam więcej atrybutów niż to, więc tak naprawdę nie chcę robić 1 dużego, jeśli oświadczenie porównujące wszystkie atrybuty, jeśli nie muszę.

Czy ktoś może mi pomóc lub doradzić, co mogę zrobić, aby znaleźć przedmioty, które pojawiają się na obu listach.

Dzięki

Odpowiedz

24

Zakładając, że obiekt ma tylko atrybut title które są istotne dla równości, trzeba zaimplementować metodę __eq__ następująco:

class YourObject: 
    [...] 
    def __eq__(self, other): 
     return self.title == other.title 

Oczywiście, jeśli masz więcej atrybutów, które są istotne dla równości, ty musi również zawierać te. Możesz również rozważyć wdrożenie __ne__ i __cmp__ dla zachowania zgodnego.

5

set intersection zrobi to.

>>> x=[1,2,3,4] 
>>> y=[3,4,5,6] 
>>> for i in set(x) & set(y): 
...  print "item %d in both lists" %i 
... 
item 3 in both lists 
item 4 in both lists 
+3

Myślę, że jego problemem jest równość obiektów, a nie samo znalezienie :) – extraneon

+3

OP zawiera listę obiektów, a nie listy typów atomowych. Jeśli spróbujesz swojego kodu z obiektami, które nie mają zdefiniowanego '__hash__', to nie zadziała, tak jak kod OP nie działa z listami obiektów, dla których nie ma zdefiniowanego' __eq__' lub '__cmp__'. – hughdbrown

9

W przypadku, gdy obiekty nie są takie same instancji, trzeba zaimplementować metodę __eq__ dla python, aby móc powiedzieć, kiedy 2 obiekty są rzeczywiście równe.

Oczywiście większość typów bibliotek, takich jak łańcuchy i listy, ma już zaimplementowane __eq__, co może być powodem, dla którego porównywanie tytułów działa dla Ciebie (czy są one ciągami?).

Aby uzyskać więcej informacji, patrz python documentation.
Oto random example dla .

+0

tak, nie są one tym samym przypadkiem. Czy możesz podać przykład funkcji __eq__, ponieważ jestem całkiem nowy w Pythonie – John

+0

@John - Dodałem link do przykładu. Po prostu szukanie google code search dla "def __eq__" rozwiązało to dla mnie :) – abyx

4

wyszukiwanie obiektów, które pojawiają się na obu listach:

l1 = [1,2,3,4,5] 
l2 = [3,4,5] 
common = set(l1).intersection(set(l2)) 

połączeniu z realizacją __eq__ na obiekcie jak inni sugerowane.

0

Spróbuj wykonać następujące czynności:

list1 = [item1, item2, item3] 
list2 = [item3, item4, item5] 
for item in list1: 
    if item in list2: 
     print "item %s in both lists" % item 
2
matches = [x for x in listA if x in listB] 
+0

, chyba że źle rozumiem, jak działa "in", środowisko uruchomieniowe tego będzie produktem długości list, co może być złe. – shabbychef

3

Trzeba napisać __eq__ funkcję zdefiniować sposób, aby porównać obiektów dla równości. Jeśli chcesz sortować, to powinnaś mieć funkcję __cmp__ i ma to sens, aby implementować __eq__ pod względem __cmp__.

def __eq__(self, other): 
    return cmp(self, other) == 0 

Należy prawdopodobnie również wdrożyć __hash__, a na pewno powinien, jeśli planujesz umieścić swoje obiekty do zbioru lub słownika.Domyślnym __hash__ dla obiektów jest id(), co sprawia, że ​​wszystkie obiekty są unikalne (tzn. Unikalność nie jest oparta na zawartości obiektu).

Napisałem klasę bazową/interfejs dla klasy, która wykonuje tego rodzaju porównanie równoważności. może okazać się przydatne:

class Comparable(object): 
    def attrs(self): 
     raise Exception("Must be implemented in concrete sub-class!") 
    def __values(self): 
     return (getattr(self, attr) for attr in self.attrs()) 
    def __hash__(self): 
     return reduce(lambda x, y: 37 * x + hash(y), self.__values(), 0) 
    def __cmp__(self, other): 
     for s, o in zip(self.__values(), other.__values()): 
      c = cmp(s, o) 
      if c: 
       return c 
     return 0 
    def __eq__(self, other): 
     return cmp(self, other) == 0 
    def __lt__(self, other): 
     return cmp(self, other) < 0 
    def __gt__(self, other): 
     return cmp(self, other) > 0 

if __name__ == '__main__': 
    class Foo(Comparable): 
     def __init__(self, x, y): 
      self.x = x 
      self.y = y 
     def attrs(self): 
      return ('x', 'y') 
     def __str__(self): 
      return "Foo[%d,%d]" % (self.x, self.y) 

    def foo_iter(x): 
     for i in range(x): 
      for j in range(x): 
       yield Foo(i, j) 

    for a in foo_iter(4): 
     for b in foo_iter(4): 
      if a<b: print "%(a)s < %(b)s" % locals() 
      if a==b: print "%(a)s == %(b)s" % locals() 
      if a>b: print "%(a)s > %(b)s" % locals() 

Klasa pochodna musi implementować attrs() która zwraca krotki lub listę atrybutów obiektu, które przyczyniają się do jego tożsamości (tj niezmienne cechy, które czynią go co to jest). Co najważniejsze, kod poprawnie obsługuje równoważność, gdy istnieje wiele atrybutów, a jest to stary kod szkolny, który często jest nieprawidłowo wykonywany.

Powiązane problemy