Python: Symmetrical Difference Between List of Sets of Strings

2.6k views Asked by At

I have a list that contains multiple sets of strings, and I would like to find the symmetric difference between each string and the other strings in the set.

For example, I have the following list:

targets = [{'B', 'C', 'A'}, {'E', 'C', 'D'}, {'F', 'E', 'D'}]

For the above, desired output is:

[2, 0, 1]

because in the first set, A and B are not found in any of the other sets, for the second set, there are no unique elements to the set, and for the third set, F is not found in any of the other sets.

I thought about approaching this backwards; finding the intersection of each set and subtracting the length of the intersection from the length of the list, but set.intersection(*) does not appear to work on strings, so I'm stuck:

set1 = {'A', 'B', 'C'}
set2 = {'C', 'D', 'E'}
set3 = {'D', 'E', 'F'}

targets = [set1, set2, set3]

>>> set.intersection(*targets)
set()
3

There are 3 answers

1
Blckknght On BEST ANSWER

The issue you're having is that there are no strings shared by all three sets, so your intersection comes up empty. That's not a string issue, it would work the same with numbers or anything else you can put in a set.

The only way I see to do a global calculation over all the sets, then use that to find the number of unique values in each one is to first count all the values (using collections.Counter), then for each set, count the number of values that showed up only once in the global count.

from collections import Counter

def unique_count(sets):
    count = Counter()
    for s in sets:
        count.update(s)
    return [sum(count[x] == 1 for x in s) for s in sets]
1
Pavan Chandaka On

Try something like below:

Get symmetric difference with every set. Then intersect with the given input set.

def symVal(index,targets):
    bseSet = targets[index] 
    symSet = bseSet  
    for j in range(len(targets)):
        if index != j:
            symSet =  symSet  ^ targets[j] 
    print(len(symSet & bseSet))

for i in range(len(targets)):
    symVal(i,targets)
2
Unsolved Cypher On

Your code example doesn't work because it's finding the intersection between all of the sets, which is 0 (since no element occurs everywhere). You want to find the difference between each set and the union of all other sets. For example:

set1 = {'A', 'B', 'C'}
set2 = {'C', 'D', 'E'}
set3 = {'D', 'E', 'F'}


targets = [set1, set2, set3]

result = []

for set_element in targets:
    result.append(len(set_element.difference(set.union(*[x for x in targets if x is not set_element]))))

print(result)

(note that the [x for x in targets if x != set_element] is just the set of all other sets)