NepNep
NepNep

Reputation: 274

Unique elements of multiple sets

I have a list of sets like below. I want to write a function to return the elements that only appear once in those sets. The function I wrote kinda works. I am wondering, is there better way to handle this problem?

s1 = {1, 2, 3, 4}
s2 = {1, 3, 4}
s3 = {1, 4}
s4 = {3, 4}
s5 = {1, 4, 5}

s = [s1, s2, s3, s4, s5]

def unique(s):
    temp = []
    for i in s:
        temp.extend(list(i))

    c = Counter(temp)
    result = set()
    for k,v in c.items():
        if v == 1:
            result.add(k)

    return result

unique(s) # will return {2, 5}

Upvotes: 6

Views: 1812

Answers (4)

CSQL
CSQL

Reputation: 106

I think the proposed solution is similar to what @Bobby Ocean suggested but not as compressed. The idea is to loop over the complete set array "s" to compute all the subset differences for each target subset "si" (avoiding itself). For example starting with s1 we compute st = s1-s2-s3-s4-s5 and starting with s5 we have st=s5-s1-s2-s3-s4. The logic behind is that due to the difference, for each target subset "si" we only keep the elements that are unique to "si" (compared to the other subsets). Finally result is the set of the union of these uniques elements.

result= set()
for si in s: # target subset
    st=si
    for sj in s: # the other subsets 
        if sj!=si: # avoid itself
            st = st-sj #compute differences
    result=result.union(st)

Upvotes: 0

abc
abc

Reputation: 11929

You can use directly a Counter and then get the elements that only appear once.

from collections import Counter
import itertools
c = Counter(itertools.chain.from_iterable(s)) 
res = {k for k,v in c.items() if v==1}
# {2, 5}

Upvotes: 7

DYZ
DYZ

Reputation: 57033

I love the Counter-based solution by @abc. But, just in case, here is a pure set-based one:

result = set() 
for _ in s: 
    result |= s[0] - set.union(*s[1:]) 
    s = s[-1:] + s[:-1] # shift the list of sets
#{2, 5}

This solution is about 6 times faster but cannot be written as a one-liner.

Upvotes: 2

Bobby Ocean
Bobby Ocean

Reputation: 3294

set.union(*[i-set.union(*[j for j in s if j!=i]) for i in s])

Upvotes: 0

Related Questions