ultron
ultron

Reputation: 443

set operation on a list of elements

I have a list containing thousands of sets similar to this:

set_list = [a, b, c, d]

each set in the list look something like this:

a = set([1, 2, 3, 4, 5])
b = set([4, 5, 6, 7, 7, 9])
c = set([1, 2, 6, 8, 10, 12, 45])
d = set([11, 3, 23, 3, 4, 44])

I would like to do the set operation: X-(YUZUAUB......etc) for every set in the list, for example, this would look something like this: after applying this operation on all elements in set_list the new elements look like this:

a = a.difference(b.union(c, d))
b = b.difference(c.union(a, d))
c = c.difference(d.union(b, a))
d = d.difference(a.union(c, b))

how do i accomplish this?

Upvotes: 5

Views: 3770

Answers (4)

NPE
NPE

Reputation: 500357

One possibility is to make use of the multiset module to precompute the multiset union of all elements in set_list, like so:

from multiset import Multiset
union = sum(set_list, Multiset())
set_list = [s - (union - s) for s in set_list]

Here, union - s computes the Y ∪ Z ∪ A ∪ B... in your notation.

See Aran-Fey's answer for the same method implemented (more verbosely) using only the standard library.

Upvotes: 3

BPL
BPL

Reputation: 9863

[value - {item for subset in set_list[0:index] + set_list[index + 1:] for item in subset} for index, value in enumerate(set_list)]

which means:

result = []
for index, value in enumerate(set_list):
    union = {
        item
        for subset in set_list[0:index] + set_list[index + 1:]
        for item in subset
    }
    result.append(value - union)

print(result)

Outputs:

[set(), {9, 7}, {8, 10, 12, 45}, {11, 44, 23}]

Upvotes: 1

Aran-Fey
Aran-Fey

Reputation: 43166

This is a re-implementation of NPE's answer using collections.Counter from the standard library:

from collections import Counter

def mutual_difference(set_list):
    # create a multiset out of the union of all sets
    union = Counter()
    for s in set_list:
        union.update(s)

    new_set_list = []
    for s in set_list:
        # subtract s from the union and discard 0-count elements
        union.subtract(s)
        union += {}

        # take the difference
        new_set_list.append(s.difference(union))

        # add s to the union again
        union.update(s)

    return new_set_list

Example:

>>> mutual_difference([{1,2}, {2,3}, {1,4,5}])
[set(), {3}, {4, 5}]

Upvotes: 1

Tomas Farias
Tomas Farias

Reputation: 1343

If I'm understanding correctly, you want the difference for each set and the union of the rest of the sets. I would use a loop and functools.reduce and operator.or_:

Setup

import functools
import operator

a = set([1, 2, 3, 4, 5])
b = set([4, 5, 6, 7, 7, 9])
c = set([1, 2, 6, 8, 10, 12, 45])
d = set([11, 3, 23, 3, 4, 44])
set_list = [a, b, c, d]

Loop and save results

# I don't know what you want to do with the results so
# I'll save them in a list...
results = [] 
for i in set_list:
    list_copy = list(set_list)
    list_copy.remove(i)
    r = i - functools.reduce(operator.or_, list_copy)
    results.append(r)

print(results)
# prints [set(), {9, 7}, {8, 10, 12, 45}, {11, 44, 23}]

Upvotes: 1

Related Questions