给定 2 个迭代/列表,目标是从两个列表中提取共同和不同的元素。
例如,给定:
x, y = [1,1,5,2,2,3,4,5,5], [2,3,4,5]
目标是实现:
common = [2,3,4,5]
x_only = [1,1,5,2,5]
y_only = []
说明:
2
时,x有2个计数,y有1个计数,因此[2]
将是公共的,而另一个[2]
将在x_only中。5
,x 有 3 个计数,y 有 1 个计数。所以 [5]
将很常见,而另一个 [5,5]
将在 x_only 中。common
、x_only
和 y_only
的顺序并不重要。我已经尝试过:
from collections import Counter
x, y = [1,1,5,2,3,4,5], [2,3,4,5]
x_only = list((Counter(x) - Counter(y)).elements())
y_only = list((Counter(y) - Counter(x)).elements())
common = list((Counter(x) & Counter(y)).elements())
上述尝试达到了目的,但重复多组/计数器减法和交集似乎有点多余。它适用于小型可迭代对象,但不适用于大型列表,例如1-100 亿项。
这是一个利用一些列表理解的解决方案
x, y = [1,1,5,2,3,4,5], [2,3,4,5]
x_only = [n for n in x if n not in y]
y_only = [n for n in y if n not in x]
common = [n for n in x if n in x and n in y]
print(x_only, y_only, common)
# => [1, 1] [] [5, 2, 3, 4, 5]
请注意,
x_only
不包括2
或5
,因为这些数字确实出现在列表中y
...如果您想要那个结果,您将不会得到它。
您的解决方案很好,只需通过仅构造每个唯一的
Counter
一次,通过使交集first来消除冗余,这样就可以减少组成唯一结果的工作,这将使您可以就地完成大部分工作(所以只构造了三个独特的Counter
,而不是五个):
from collections import Counter
x, y = [1,1,5,2,3,4,5], [2,3,4,5]
cx = Counter(x)
cy = Counter(y)
both = cx & cy
cx -= both
cy -= both
x_only = list(cx.elements())
y_only = list(cy.elements())
common = list(both.elements())
线路更多,但完成的工作更少,并且任何给定的线路都不那么复杂。