pythonset-operations

How to get the symmetric difference of more than 2 lists?


I want to get all exclusive elements between all my lists. So if I have 3 lists like:

list1 = [1, 3, 2]
list2 = ["a", 1, 3]
list3 = [2, 0]

My output should be:

['a', 0]

I tried to do symmetric differencing with all of the lists like:

set(list1) ^ set(list2) ^ set(list3)

But this doesn´t work well.

Also I tried:

def exclusive(*lista):
    excl = set(lista[0])
    for idx in range(len(lista)):
        excl ^= set(lista[idx])
    return excl

That works the same as the first method but it doesn´t produce what I want.

Then I tried (set(list1) ^ set(list2)) ^ (set(list2) ^ (set(list3)) and found that it's not the same as what I first tried.

EDIT:

I give 3 list as an example but function take undifined number of arguments


Solution

  • You could also take a non-set approach using 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]
    

    Use itertools.chain to flatten your lists together and use Counter to count the occurrences. Keep only those where the count is 1.


    Update: Here is a better example that demonstrates why the other methods do not work.

    list1 = [1, 3, 2]
    list2 = ["a", 1, 3]
    list3 = [2, 0]
    list4 = [1, 4]
    all_lists = [list1, list2, list3, list4]
    

    Based on your criteria, the correct answer is:

    print([k for k, v in Counter(chain(*all_lists)).items() if v==1])
    #['a', 4, 0]
    

    Using reduce(set.symmetric_difference, ...):

    sets = map(set, all_lists)
    print(reduce(set.symmetric_difference, sets))
    #{0, 1, 4, 'a'}
    

    Using the symmetric difference minus the intersection:

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