我有2个实例列表 列表1 list2中
每个实例都包含id,name等变量...... 我正在遍历list2,我想找到list1中不存在的条目。 例如..
用于list2中的条目: 如果list1中的entry.id:
我希望在没有双循环的情况下找到一种方法。有一个简单的方法吗?
答案 0 :(得分:7)
我可能会这样做:
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))算法。
答案 1 :(得分:4)
只是一个想法...
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的方法更快,但在__hash__
中定义__eq__
和Foo
会导致代码更易读。
答案 2 :(得分:1)
您可以使用filter
difference = filter(lambda x: x not in list1, list2)
在Python 2中,它将返回您想要的列表。在Python 3中,它将返回一个filter
对象,您可能希望将其转换为列表。
答案 3 :(得分:0)
或许这样的事情?
In [1]: list1 = [1,2,3,4,5]
In [2]: list2 = [4,5,6,7]
In [3]: final_list = [x for x in list1 if x not in list2]