I have a list of objects in Python. I then have another list of objects. I want to go through the first list and see if any items appear in the second list.
I thought I could simply do
for item1 in list1:
for item2 in list2:
if item1 == item2:
print "item %s in both lists"
However this does not seem to work. Although if I do:
if item1.title == item2.title:
it works okay. I have more attributes than this though so don't really want to do 1 big if statement comparing all th开发者_StackOverflowe attributes if I don't have to.
Can anyone give me help or advise on what I can do to find the objects which appear in both lists.
Thanks
Assuming that your object has only a title
attribute which is relevant for equality, you have to implement the __eq__
method as follows:
class YourObject:
[...]
def __eq__(self, other):
return self.title == other.title
Of course if you have more attributes that are relevant for equality, you must include those as well. You might also consider implementing __ne__
and __cmp__
for consistent behaviour.
In case the objects are not the same instance, you need to implement the __eq__
method for python to be able to tell when 2 objects are actually equal.
Of course that most library types, such as strings and lists already have __eq__
implemented, which may be the reason comparing titles works for you (are they strings?).
For further information see the python documentation.
Here is a random example for __eq__
.
set intersection will do for that.
>>> 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
Finding objects who appear in both lists:
l1 = [1,2,3,4,5]
l2 = [3,4,5]
common = set(l1).intersection(set(l2))
Combine this with the __eq__
implementation on the object as the others suggested.
You need to write an __eq__
function to define how to compare objects for equality. If you want sorting, then yo should have a __cmp__
function, and it makes the most sense to implement __eq__
in terms of __cmp__
.
def __eq__(self, other):
return cmp(self, other) == 0
You should probably also implement __hash__
, and you definitely should if you plan to put your objects into a set or dictionary. The default __hash__
for objects is id(), which effectively makes all objects unique(i.e. uniqueness is not based on object contents).
I wrote a base class/interface for a class that does this sort of equivalence comparison. You may find it useful:
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()
The derived class must implement attrs()
that returns a tuple or list of the object's attributes that contribute to its identity (i.e. unchanging attributes that make it what it is). Most importantly, the code correctly handles equivalence where there are multiple attributes, and this is old school code that is often done incorrectly.
matches = [x for x in listA if x in listB]
Try the following:
list1 = [item1, item2, item3]
list2 = [item3, item4, item5]
for item in list1:
if item in list2:
print "item %s in both lists" % item
精彩评论