Python如何检查一个对象是否在对象列表中?

22

我有一个Python对象列表。然后我有另一个对象列表。我想遍历第一个列表,查看是否有任何项出现在第二个列表中。

我以为我可以简单地执行

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

但是这似乎不起作用。虽然如果我这样做:

if item1.title == item2.title:

它可以正常工作。不过我有更多的属性,所以如果没有必要的话,我不想使用一个大的if语句来比较所有属性。

有人能帮助或者建议我如何找到同时出现在两个列表中的对象吗?

谢谢

7个回答

41

假设你的对象只有一个与相等性相关的title属性,你需要按照下面的方式实现__eq__方法:

class YourObject:
    [...]
    def __eq__(self, other):
        return self.title == other.title
当然,如果你有更多与相等相关的属性,你也必须将它们包含在内。你还可以考虑实现 __ne____cmp__ 以保持一致的行为。

10

如果对象不是同一个实例,你需要实现__eq__方法让Python能够判断两个对象是否相等。

当然,大多数库类型,如字符串和列表,已经实现了__eq__,这可能是你比较标题有效的原因(它们是字符串吗?)。

有关更多信息,请参见Python文档
下面是一个__eq__随机示例


是的,它们不是同一个实例。你能给我举个例子来说明 eq 函数吗?因为我对 Python 还很新。 - John
@John - 我已经添加了一个示例链接。只需在 Google 代码搜索中搜索“def __eq__”即可解决这个问题 :) - abyx

5

集合交集可以完成这个任务。

>>> 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
我认为他的问题在于对象相等性,而不仅仅是查找 :) - extraneon
4
OP有一些对象列表,而不是原子类型列表。如果您尝试使用没有定义__hash__的对象运行代码,它将无法工作,就像OP的代码无法处理没有定义__eq____cmp__的对象列表一样。 - hughdbrown

4

查找出同时出现在两个列表中的对象:

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

将此与其他人建议的对象上的__eq__实现相结合。

3

你需要编写一个__eq__函数来定义如何比较对象的相等性。如果你想排序,那么应该有一个__cmp__函数,并且最好是用__cmp__来实现__eq__

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

如果您计划将对象放入集合或字典中,那么您可能还应该实现__hash__,如果这样做,则绝对需要。对象的默认哈希值是id(),这使得所有对象都是唯一的(即唯一性不基于对象内容)。

我为执行此类等价比较的类编写了一个基类/接口。您可能会发现它很有用:

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

派生类必须实现attrs()方法,该方法返回一个元组或列表,其中包含对象的属性,这些属性对其身份(即使其成为什么)做出了贡献。最重要的是,代码正确处理具有多个属性的等价性,这是老派的代码,经常被错误地执行。

2
matches = [x for x in listA if x in listB]

除非我误解了'in'的工作原理,否则这个程序的运行时间将是列表长度的乘积,这可能会很糟糕。 - shabbychef

0

请尝试以下方法:

list1 = [item1, item2, item3]
list2 = [item3, item4, item5]
for item in list1:
    if item in list2:
        print "item %s in both lists" % item

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接