如何获得两个以上列表的对称差异?
How to get the symmetric difference of more than 2 lists?
我想获得所有列表之间的所有独占元素。所以如果我有 3 个列表,例如:
list1 = [1, 3, 2]
list2 = ["a", 1, 3]
list3 = [2, 0]
我的输出应该是:
['a', 0]
我尝试对所有列表进行对称差分,例如:
set(list1) ^ set(list2) ^ set(list3)
但这并不奏效。
我也试过:
def exclusive(*lista):
excl = set(lista[0])
for idx in range(len(lista)):
excl ^= set(lista[idx])
return excl
这与第一种方法的工作原理相同,但它不会产生我想要的结果。
然后我试了(set(list1) ^ set(list2)) ^ (set(list2) ^ (set(list3))
发现和我第一次试的不一样
编辑:
我以 3 列表为例,但函数采用未定义数量的参数
3个集合的对称差减去3个集合的交集才能得到独占项:
set1 = set(list1)
set2 = set(list2)
set3 = set(list3)
(set1 ^ set2 ^ set3) - (set1 & set2 & set3)
因此给定:
list1 = [1,3,2]
list2 = ["a",1,3]
list3 = [2,0,1]
这个returns:
{0, 'a'}
而您 set1 ^ set2 ^ set3
的尝试会错误 return:
{0, 1, 'a'}
您也可以使用 collections.Counter
:
的非集合方法
from itertools import chain
from collections import Counter
res = [k for k, v in Counter(chain(list1, list2, list3)).items() if v==1]
print(res)
#['a', 0]
使用 itertools.chain
将您的列表拼合在一起,并使用 Counter
计算出现次数。只保留计数为 1 的那些。
Update:这里有一个更好的例子来说明为什么其他方法不起作用。
list1 = [1, 3, 2]
list2 = ["a", 1, 3]
list3 = [2, 0]
list4 = [1, 4]
all_lists = [list1, list2, list3, list4]
根据您的标准,正确答案是:
print([k for k, v in Counter(chain(*all_lists)).items() if v==1])
#['a', 4, 0]
使用reduce(set.symmetric_difference, ...)
:
sets = map(set, all_lists)
print(reduce(set.symmetric_difference, sets))
#{0, 1, 4, 'a'}
使用对称差减去交集:
set1 = set(list1)
set2 = set(list2)
set3 = set(list3)
set4 = set(list4)
print((set1 ^ set2 ^ set3 ^ set4) - (set1 & set2 & set3 & set4))
#{0, 1, 4, 'a'}
这主要可以通过集合操作来完成,但我更喜欢 @pault 的答案的简单性。为了得到任意数量的集合的对称差,你可以找到所有集合组合之间的交集,然后从所有集合的并集中得到那个组合交集的对称差。
from itertools import combinations
def symdiff(*sets):
union = set()
union.update(*sets)
intersect = set()
for a, b in combinations(sets, 2):
intersect.update(a.intersection(b))
return intersect.symmetric_difference(union)
distincts = symdiff(set([1, 3, 2]), set(['a', 1, 3]), set([2, 0]))
print(distincts)
# {0, 'a'}
以下是更好的示例输入,其中集合的简单顺序对称差异不会提供相同的结果。
distincts = symdiff(set([1, 3, 2, 0]), set(['a', 1, 3, 0]), set([2, 0]))
print(distincts)
# {'a'}
我想获得所有列表之间的所有独占元素。所以如果我有 3 个列表,例如:
list1 = [1, 3, 2]
list2 = ["a", 1, 3]
list3 = [2, 0]
我的输出应该是:
['a', 0]
我尝试对所有列表进行对称差分,例如:
set(list1) ^ set(list2) ^ set(list3)
但这并不奏效。
我也试过:
def exclusive(*lista):
excl = set(lista[0])
for idx in range(len(lista)):
excl ^= set(lista[idx])
return excl
这与第一种方法的工作原理相同,但它不会产生我想要的结果。
然后我试了(set(list1) ^ set(list2)) ^ (set(list2) ^ (set(list3))
发现和我第一次试的不一样
编辑:
我以 3 列表为例,但函数采用未定义数量的参数
3个集合的对称差减去3个集合的交集才能得到独占项:
set1 = set(list1)
set2 = set(list2)
set3 = set(list3)
(set1 ^ set2 ^ set3) - (set1 & set2 & set3)
因此给定:
list1 = [1,3,2]
list2 = ["a",1,3]
list3 = [2,0,1]
这个returns:
{0, 'a'}
而您 set1 ^ set2 ^ set3
的尝试会错误 return:
{0, 1, 'a'}
您也可以使用 collections.Counter
:
from itertools import chain
from collections import Counter
res = [k for k, v in Counter(chain(list1, list2, list3)).items() if v==1]
print(res)
#['a', 0]
使用 itertools.chain
将您的列表拼合在一起,并使用 Counter
计算出现次数。只保留计数为 1 的那些。
Update:这里有一个更好的例子来说明为什么其他方法不起作用。
list1 = [1, 3, 2]
list2 = ["a", 1, 3]
list3 = [2, 0]
list4 = [1, 4]
all_lists = [list1, list2, list3, list4]
根据您的标准,正确答案是:
print([k for k, v in Counter(chain(*all_lists)).items() if v==1])
#['a', 4, 0]
使用reduce(set.symmetric_difference, ...)
:
sets = map(set, all_lists)
print(reduce(set.symmetric_difference, sets))
#{0, 1, 4, 'a'}
使用对称差减去交集:
set1 = set(list1)
set2 = set(list2)
set3 = set(list3)
set4 = set(list4)
print((set1 ^ set2 ^ set3 ^ set4) - (set1 & set2 & set3 & set4))
#{0, 1, 4, 'a'}
这主要可以通过集合操作来完成,但我更喜欢 @pault 的答案的简单性。为了得到任意数量的集合的对称差,你可以找到所有集合组合之间的交集,然后从所有集合的并集中得到那个组合交集的对称差。
from itertools import combinations
def symdiff(*sets):
union = set()
union.update(*sets)
intersect = set()
for a, b in combinations(sets, 2):
intersect.update(a.intersection(b))
return intersect.symmetric_difference(union)
distincts = symdiff(set([1, 3, 2]), set(['a', 1, 3]), set([2, 0]))
print(distincts)
# {0, 'a'}
以下是更好的示例输入,其中集合的简单顺序对称差异不会提供相同的结果。
distincts = symdiff(set([1, 3, 2, 0]), set(['a', 1, 3, 0]), set([2, 0]))
print(distincts)
# {'a'}