Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何获得两个以上列表的对称差?_Python_Set Operations - Fatal编程技术网

Python 如何获得两个以上列表的对称差?

Python 如何获得两个以上列表的对称差?,python,set-operations,Python,Set Operations,我想在我的所有列表之间获得所有独占元素。因此,如果我有3个列表,如: list1 = [1, 3, 2] list2 = ["a", 1, 3] list3 = [2, 0] set(list1) ^ set(list2) ^ set(list3) 我的输出应该是: ['a', 0] 我尝试对所有列表进行对称差分,如: list1 = [1, 3, 2] list2 = ["a", 1, 3] list3 = [2, 0] set(list1) ^ set(list2) ^ set(li

我想在我的所有列表之间获得所有独占元素。因此,如果我有3个列表,如:

list1 = [1, 3, 2]
list2 = ["a", 1, 3]
list3 = [2, 0]
set(list1) ^ set(list2) ^ set(list3)
我的输出应该是:

['a', 0]
我尝试对所有列表进行对称差分,如:

list1 = [1, 3, 2]
list2 = ["a", 1, 3]
list3 = [2, 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]
这将返回:

{0, 'a'}
然而,您尝试设置1^set2^set3将错误返回:

{0, 1, 'a'}

您还可以使用
集合采用非集合方法。计数器

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的事件


更新:下面是一个更好的示例,演示了其他方法不起作用的原因

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]
使用
减少(set.symmetric_difference,…)

使用对称差减去交点:

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'}

这主要可以通过集合运算来实现,但我更喜欢简单的答案。为了获得任意数量集合的对称差,可以找到所有集合组合之间的交集,然后从所有集合的并集中获得该组合交集的对称差

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'}

“不好用”是什么意思?
set(list1)^set(list2)^set(list3)
工作得很好。如果您想要一个列表作为结果,请将结果转换为列表:
list(set(list1)^…)
@Aran Fey不,它不能完全正常工作。3个集合上的对称差分将返回3个集合的交集以及独占项。更改输入值将更好地突出显示2个以上集合的顺序对称差分所导致的问题。例如,尝试建议的解决方案按此顺序输入以下内容:
[1,3,2,0]
[a',1,3,0]
[2,0]
。在这种情况下,唯一应产生的排他元素是“a”@DYZ我更喜欢在集合中。我只是想要元素组。我仍然认为这在一般情况下不起作用-我更新了我的答案,以包括一个示例来演示这一点。编辑:在我更新的示例中,问题是
set1&set2&set3&set4
返回一个空集。是的,我应该注意到该方法仅适用于3个集合。它不适用于函数如果一个列表中有两个或多个相等的元素:
[1]
[1,2,2]
将返回一个空列表,而不是
[2,2]
@MykolaZotko这是一个正确的说法,但这不是我解释问题要求的方式,因为OP在尝试将列表转换为集合。@pault我转换列表是为了消除重复问题elements@pault我几乎能理解你的答案,但不要反驳@DanielMuñoz-是
dict
的子类,因此
Counter.items()
返回键值对的视图(有点像列表)。对于
Counter
,键是元素,值是计数。