Python:比较2个实例列表

2024-03-28 10:20:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个实例列表:

list1
list2

每个实例都包含诸如id、name等变量。。。

我正在遍历list2,希望找到list1中不存在的条目。

例如。。

for entry in list2:
  if entry.id in list1:
    <do something> 

我希望能找到一种不需要重复循环的方法。有简单的方法吗?


Tags: 实例方法nameinid列表forif
4条回答

您可以使用filter

difference = filter(lambda x: x not in list1, list2)

在Python 2中,它将返回所需的列表。在Python 3中,它将返回一个filter对象,您可能希望将其转换为列表。

只是一个想法。。。

class Foo(object):
    def __init__(self, id, name):
        self.id = id
        self.name = name
    def __repr__(self):
        return '({},{})'.format(self.id, self.name)

list1 = [Foo(1,'a'),Foo(1,'b'),Foo(2,'b'),Foo(3,'c'),]
list2 = [Foo(1,'a'),Foo(2,'c'),Foo(2,'b'),Foo(4,'c'),]

所以通常这是行不通的:

print(set(list1)-set(list2))
# set([(1,b), (2,b), (3,c), (1,a)])

但是你可以教Foo两个实例相等意味着什么:

def __hash__(self):
    return hash((self.id, self.name))

def __eq__(self, other):
    try:
        return (self.id, self.name) == (other.id, other.name)
    except AttributeError:
        return NotImplemented

Foo.__hash__ = __hash__
Foo.__eq__ = __eq__

现在:

print(set(list1)-set(list2))
# set([(3,c), (1,b)])

当然,更可能的是,您可以在类定义时在__hash__上定义__eq__Foo,而无需稍后对其进行猴子修补:

class Foo(object):
    def __init__(self, id, name):
        self.id = id
        self.name = name

    def __repr__(self):
        return '({},{})'.format(self.id, self.name)

    def __hash__(self):
        return hash((self.id, self.name))

    def __eq__(self, other):
        try:
            return (self.id, self.name) == (other.id, other.name)
        except AttributeError:
            return NotImplemented

为了满足我自己的好奇心,这里有一个基准:

In [34]: list1 = [Foo(1,'a'),Foo(1,'b'),Foo(2,'b'),Foo(3,'c')]*10000

In [35]: list2 = [Foo(1,'a'),Foo(2,'c'),Foo(2,'b'),Foo(4,'c')]*10000
In [40]: %timeit set1 = set((x.id,x.name) for x in list1); [x for x in list2 if (x.id,x.name) not in set1 ]
100 loops, best of 3: 15.3 ms per loop

In [41]: %timeit set1 = set(list1); [x for x in list2 if x not in set1]
10 loops, best of 3: 33.2 ms per loop

因此@mgilson的方法更快,尽管在Foo中定义__hash____eq__会导致更可读的代码。

我可能会这样做:

set1 = set((x.id,x.name,...) for x in list1)
difference = [ x for x in list2 if (x.id,x.name,...) not in set1 ]

其中...是实例的附加(哈希)属性——您需要包含足够多的属性以使其唯一。

这将使用O(N*M)算法并将其转换为O(max(N,M))算法。

我可能会这样做:

set1 = set((x.id,x.name,...) for x in list1)
difference = [ x for x in list2 if (x.id,x.name,...) not in set1 ]

其中...是实例的附加(散列)属性——您需要包含足够多的属性以使其唯一。

这将使用O(N*M)算法并将其转换为O(max(N,M))算法。

相关问题 更多 >