4

我正在开发一个模块,该模块依赖于检查两个列表中是否存在任何不存在的对象。该实现应该在 Python 中。

考虑简化的对象 def:

class Foo(object):

  def __init__(self, attr_one=None, attr_two=None):
    self.attr_one = attr_one
    self.attr_two = attr_two

  def __eq__(self, other):
    return self.attr_one == other.attr_one and self.attr_two == other.attr_two

我有两个单独的列表,它们可以封装 Foo 类的多个实例,如下所示:

list1 = [Foo('abc', 2), Foo('bcd', 3), Foo('cde', 4)]
list2 = [Foo('abc', 2), Foo('bcd', 4), Foo('efg', 5)]

我需要根据 attr_one 找出一个列表中存在而另一个列表中不存在的对象。在这种情况下,下面给出了第一个列表中存在而第二个列表中缺少的项目的所需输出。

`['Foo('bcd', 3), Foo('cde', 4)]` 

同样,列表 2 中存在但列表 1 中不存在的项目

 [Foo('bcd', 4), Foo('efg', 5)]

我想知道是否有办法匹配 attr_one 的基础。

  List 1                 List 2        
  Foo('bcd', 3)          Foo('bcd', 4)
  Foo('cde', 4)          None
  None                   Foo('efg', 5)
4

3 回答 3

8

由于您已经__eq__定义了一个方法,您可以使用列表推导来查找任一列表中对象的唯一性。

print [obj for obj in list1 if obj not in list2]
于 2013-02-11T07:44:00.713 回答
4

快速比较列表以确定哪些元素存在于一个列表中而另一个不存在的一个好方法是从原始列表创建集合并获取两个集合之间的差异。为了使列表成为一个集合,它包含的对象必须是hashable,因此您必须为您的对象定义一个新__hash__()方法Foo

def __hash__(self):
    return hash((self.attr_one,self.attr_two))

请注意,由于元组是可散列的,只要attr_oneattr_two是可散列的类型,这个实现应该是相当可靠的。

现在,要确定哪些元素存在于一个列表中而不存在于另一个列表中:

set1 = set(list1)
set2 = set(list2)
missing_from_1 = set2 - set1
missing_from_2 = set1 - set2

要仅基于其中一个属性执行此操作,您可以仅使用属性本身创建集合:

set1 = set([i.attr_one for i in list1])

当然,这意味着您最终得到的结果只会告诉您attr_one一个列表中存在的值,而不是另一个列表中的值,而不是给您实际的Foo对象。然而,一旦你有了“缺失”的集合,对象本身就很容易找到:

missing_Foos = set()
for attr in missing_from_2:
    for i in list1:
        if i.attr_one == attr:
            missing_Foos.add(i)

但是,如果您有很长的列表,这可能会在计算上相当昂贵。

编辑:只有当您有非常大的列表并因此需要利用集合操作的计算效率时,使用集合才真正有用。否则,如另一个答案中所建议的那样,简单地使用列表推导可能会更简单。

于 2013-02-11T07:43:05.443 回答
1

我有两种方法可以做到这一点 - 使用sets或 with filter

class Foo(object):

    def __init__(self, attr_one=None, attr_two=None):
        self.attr_one = attr_one
        self.attr_two = attr_two

    def __eq__(self, other):
        return self.attr_one == other.attr_one and self.attr_two == other.attr_two

    def __hash__(self):
        return hash(self.attr_one)

    def __repr__(self):
        return "<Foo {} {}>".format(self.attr_one, self.attr_two)

def main():
    a = Foo('test', 1)
    b = Foo('test', 1)

    list1 = [Foo('abc', 2), Foo('bcd', 3), Foo('cde', 4)]
    list2 = [Foo('abc', 2), Foo('bcd', 4), Foo('efg', 5)]

    # With sets
    list1set = set(list1)
    list2set = set(list2)

    print list1set.intersection(list2set) 
    # Returns set([<Foo abc 2>])

    # With filter
    list2attr_one = [l.attr_one for l in list2]
    print filter(lambda x: x.attr_one in list2attr_one, list1)
    # Returns [<Foo abc 2>, <Foo bcd 3>]
于 2013-02-11T07:49:47.213 回答