Mam trzy zbiory składające się z imion i nazwisk osób uczęszczających na poszczególne przedmioty. Mam wyświetlić osoby uczęszczające na tylko jeden przedmiot. Chcę skorzystać z różnicy symetrycznej ale od dłuższego czasu szukam jak zrobić, zdefiniować różnice symetryczną dla trzech zbiorów. A^B^C nie daje pożądanego wyniku.
0
0
Użyj symmetric_difference
i difference
:
import itertools
def symm_diff_three(a, b, c):
tmp = a.union(b.union(c))
tmp1 = [x.intersection(y) for x,
y in itertools.combinations([a, b, c], 2)]
tmp2 = tmp1[0].union(tmp1[1].union(tmp1[2]))
return tmp.symmetric_difference(tmp2)
def main():
a = set([11, 1 ,5])
b = set([1, 5, 3])
c = set([3, 9, 1])
print(symm_diff_three(a, b, c)) # -> 9, 11
if __name__ == '__main__':
main()
EDYCJA: Zmieniłem rozwiązanie, trzeba znaleźć sumę wszystkich zbiorów, potem wszystkie możliwe dwuelementowe przecięcia, i od sumy odjąc te przecięcia.
EDYCJA2: W zasadzie robiąc takie coś powinno sie uogólnić na dowolną liczbę zbiorów:
import itertools
from functools import reduce
def set_union(x, y):
return x.union(y)
def symm_diff(*args):
tmp = reduce(set_union, args)
tmp1 = [x.intersection(y) for x,
y in itertools.combinations(args, 2)]
tmp2 = reduce(set_union, tmp1)
return tmp.symmetric_difference(tmp2)
1
Symetryczna różniąca dowolnej liczby zbiorów składa się z tych elementów, które występują w nieparzyście wielu z tych zbiorów, toteż nic dziwnego, że Twój początkowy pomysł nie działa. Jeśli jednak chcesz rozwiązać to zadanie sprawnie, to najlepszą metodą jest oczywiście zliczenie elementów i wykluczenie tech, które występują co najmniej dwa razy.