2010-04-01 15 views
14

Ho una lista di oggetti in Python. Poi ho un'altra lista di oggetti. Voglio passare attraverso la prima lista e vedere se alcuni elementi appaiono nella seconda lista.Python verifica se l'oggetto è in lista di oggetti

ho pensato che avrei potuto semplicemente fare

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

Tuttavia questo non sembra funzionare. Anche se lo faccio:

if item1.title == item2.title: 

funziona bene. Ho più attributi di questo però, quindi non voglio davvero fare una grande istruzione se confrontiamo tutti gli attributi se non dovessi farlo.

Qualcuno può darmi un aiuto o un consiglio su cosa posso fare per trovare gli oggetti che appaiono in entrambe le liste.

Grazie

risposta

24

Supponendo che l'oggetto ha solo un attributo title che è rilevante per l'uguaglianza, è necessario implementare il metodo __eq__ come segue:

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

Naturalmente se si dispone di più attributi che sono rilevanti per l'uguaglianza, è deve includere anche quelli. Potresti anche considerare l'implementazione di __ne__ e __cmp__ per un comportamento coerente.

5

set intersection farà per questo.

>>> 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

Penso che il suo problema sia l'uguaglianza degli oggetti, non tanto il ritrovamento :) – extraneon

+3

L'OP ha elenchi di oggetti, non elenchi di tipi atomici. Se provi il tuo codice con oggetti che non hanno definito '__hash__', non funzionerà, proprio come il codice dell'OP non funziona con elenchi di oggetti per i quali non è definito' __eq__' o '__cmp__'. – hughdbrown

9

Nel caso in cui gli oggetti non sono la stessa istanza, è necessario implementare il metodo __eq__ per Python per essere in grado di dire quando 2 oggetti sono in realtà uguali.

Ovviamente la maggior parte dei tipi di libreria, come stringhe e liste, ha già implementato __eq__, che potrebbe essere il motivo per cui i titoli di confronto funzionano per voi (sono stringhe?).

Per ulteriori informazioni vedere python documentation.
Questo è un random example per __eq__.

+0

sì, NON sono la stessa istanza. Puoi darmi un esempio della funzione __eq__ visto che sono abbastanza nuovo per Python – John

+0

@John - Ho aggiunto un link ad un esempio. Semplicemente cercando codice di ricerca google per "def __eq__" risolto per me :) – abyx

4

ricerca di oggetti che appaiono in entrambe le liste:

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

Combinate questo con il __eq__ implementazione sull'oggetto come gli altri hanno suggerito.

0

provare quanto segue:

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

a meno che non fraintendano il funzionamento di "in", il runtime per questo sarà il prodotto delle lunghezze delle liste, il che potrebbe essere negativo. – shabbychef

3

è necessario scrivere una funzione __eq__ per definire come confrontare gli oggetti per l'uguaglianza. Se si desidera ordinare, si dovrebbe avere una funzione __cmp__ e ha più senso implementare __eq__ in termini di __cmp__.

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

Probabilmente si dovrebbe anche implementare __hash__, e sicuramente dovrebbe se si prevede di mettere i vostri oggetti in un set o un dizionario.L'impostazione predefinita __hash__ per gli oggetti è id(), che rende in modo univoco tutti gli oggetti (vale a dire l'unicità non è basata sul contenuto dell'oggetto).

Ho scritto una classe base/interfaccia per una classe che esegue questo tipo di confronto di equivalenza. Si possono trovare utile:

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() 

La classe derivata deve implementare attrs() che restituisce una tupla o una lista di attributi dell'oggetto che contribuiscono alla sua identità (cioè gli attributi immutabili che lo rendono quello che è). Ancora più importante, il codice gestisce correttamente l'equivalenza dove ci sono più attributi, e questo è il codice della vecchia scuola che viene spesso fatto in modo errato.

Problemi correlati