2010-04-01 13 views
14

Tengo una lista de objetos en Python. Luego tengo otra lista de objetos. Quiero ir a la primera lista y ver si aparece algún elemento en la segunda lista.Python compruebe si el objeto está en la lista de objetos

pensé que simplemente podía hacer

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

Sin embargo esto no parece funcionar. Aunque si lo hago:

if item1.title == item2.title: 

funciona bien. Sin embargo, tengo más atributos que esto, así que realmente no quiero hacer 1 gran afirmación si comparo todos los atributos si no es necesario.

¿Alguien me puede ayudar o asesorar sobre lo que puedo hacer para encontrar los objetos que aparecen en ambas listas?

Gracias

Respuesta

24

Suponiendo que el objeto tiene solamente un atributo title que es relevante para la igualdad, hay que poner en práctica el método __eq__ de la siguiente manera:

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

Por supuesto, si usted tiene más atributos que son relevantes para la igualdad, se debe incluir esos también. También puede considerar implementar __ne__ y __cmp__ para un comportamiento consistente.

5

set intersection va a hacer por eso.

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

Creo que su problema es la igualdad de los objetos, no tanto el descubrimiento :) – extraneon

+3

El OP tiene listas de objetos, no listas de tipos atómicos. Si prueba su código con objetos que no tienen '__hash__' definido, no funcionará, del mismo modo que el código OP no funciona con listas de objetos para los cuales no hay' __eq__' o '__cmp__' definido. – hughdbrown

9

En caso de que los objetos no son la misma instancia, es necesario poner en práctica el método __eq__ para el pitón para ser capaz de decir cuando 2 objetos son en realidad iguales.

Por supuesto, la mayoría de los tipos de bibliotecas, como cadenas y listas, ya tienen implementado __eq__, lo cual puede ser el motivo por el que la comparación de títulos funciona para usted (¿son cadenas?).

Para obtener más información, consulte el python documentation.
Aquí está un random example para __eq__.

+0

sí, NO son la misma instancia. ¿Puede darme un ejemplo de la función __eq__ ya que soy bastante nuevo en Python – John

+0

@John? He agregado un enlace a un ejemplo. Simplemente buscando la búsqueda del código de google para "def __eq__" me lo resolvió :) – abyx

4

Búsqueda de objetos que aparecen en ambas listas:

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

combinar esto con la __eq__ aplicación sobre el objeto como los otros sugirieron.

0

intente lo siguiente:

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 menos que malinterprete cómo funciona 'en', el tiempo de ejecución para esto va a ser el producto de las longitudes de la lista, lo que podría ser malo. – shabbychef

3

tiene que escribir una función __eq__ para definir cómo comparar objetos por la igualdad. Si desea clasificar, entonces debe tener una función __cmp__, y tiene más sentido implementar __eq__ en términos de __cmp__.

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

Debería probablemente aplicar __hash__, y que sin duda debe si va a poner los objetos en un conjunto o diccionario.El valor predeterminado __hash__ para objetos es id(), que efectivamente hace que todos los objetos sean únicos (es decir, la exclusividad no se basa en el contenido del objeto).

Escribí una clase base/interfaz para una clase que hace este tipo de comparación de equivalencia. Puede que le resulte útil:

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 clase derivada debe aplicar attrs() que devuelve una tupla o una lista de los atributos del objeto que contribuyen a su identidad (es decir, atributos inmutables que hacen que sea lo que es). Lo más importante es que el código maneja correctamente la equivalencia cuando hay múltiples atributos, y este es un código de la vieja escuela que a menudo se hace incorrectamente.

Cuestiones relacionadas