Welcome, guest | Sign In | My Account | Store | Cart

This recipe provides a subclass of set which implements __mul__ and __pow__ to support the computation of set products. When multiplying two sets together, a new set is produced with elements which are the inter-set pairs.

Python, 33 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import operator


class Set(set):
    def __mul__(self, other):
        if not isinstance(other, set):
            return NotImplemented
        return Set(self._join_elements(x, y) for x in self for y in other)

    def __pow__(self, amount):
        if not isinstance(amount, int):
            return NotImplemented
        return reduce(operator.mul, (self for _ in xrange(amount)))

    def _join_elements(self, x, y):
        if not isinstance(x, tuple):
            x = (x,)
        if not isinstance(y, tuple):
            y = (y,)
        return x + y

    def __repr__(self):
        s = set.__repr__(self)
        return '%s(%s' % (self.__class__.__name__, s.split('(', 1)[1])


def main():
    # binary numbers of 3 bits
    s = Set([0, 1])
    print s ** 3

if __name__ == '__main__':
    main()
 

Products are a useful thing to compute when working with sets. For example, the set of binary numbers of size n can be computed as {0, 1} ** n.

2 comments

Gabriel Genellina 14 years ago  # | flag

Nice recipe!

Note that starting with Python 2.6, you can achieve the same thing using itertools.product:

py> s = Set(['a','b'])
py> t = Set([1,2,3])
py> s*t
Set([('a', 1), ('b', 2), ('b', 3), ('b', 1), ('a', 3), ('a', 2)])

py> s = set(['a','b'])
py> t = set([1,2,3])
py> set(product(s,t))
set([('a', 1), ('b', 2), ('b', 3), ('b', 1), ('a', 3), ('a', 2)])
Paul G (author) 14 years ago  # | flag

Hi Gabriel,

Thanks for the comment. itertools.product is great, but it doesn't quite achieve the same thing; this recipe joins tuples if they're there:

>>> ab = Set(['a', 'b'])
>>> st = Set(['s', 't'])
>>> xy = Set(['x', 'y'])

>>> ab_st = ab * st
>>> ab_st * xy
Set([('a', 's', 'x'), ('a', 't', 'x'), ('a', 's', 'y'), ...])

>>> ab_st = product(ab, st)
>>> set(product(ab_st, xy))
set([(('b', 't'), 'y'), (('a', 's'), 'y'), (('b', 's'), 'x'), ...])

But the main thing about this recipe is the notation that it allows for (x * y). Operator overloading is a great language feature.