Question

In Python how can I write a generic function to generate the Cartesian product of the same set repeated n times without using recursion and without using the itertools package? The function should take two parameters: the set and the n times.

e.g.:

set1={'a','b'}
print({(x,y) for x in set1 for y in set1})

{('a', 'b'), ('b', 'a'), ('b', 'b'), ('a', 'a')}

print({(x,y,z) for x in set1 for y in set1 for z in set1})

{('b', 'a', 'b'), ('a', 'b', 'a'), ('a', 'a', 'a'), ('b', 'a', 'a'), ('a', 'a', 'b'), ('b', 'b', 'a'), ('b', 'b', 'b'), ('a', 'b', 'b')}

etc.

But also:

set2={'a','b','c'}
print({(x,y,z) for x in set2 for y in set2 for z in set2})
print({(w,x,y,z) for w in set2 for x in set2 for y in set2 for z in set2})

etc.

Was it helpful?

Solution

You can generalize the comprehension-based technique you're already using by iteratively building up the result:

   def cartesian_product(s, dim):
        if dim == 0:
            return set()
        res = [(e,) for e in s]
        for i in range(dim - 1):
            res = [e + (f,) for e in res for f in s]
        return set(res)

    ex = {1,2,3}

    for i in range(4):
        print cartesian_product(ex, i)

Output:

set([])
set([(2,), (3,), (1,)])
set([(1, 2), (3, 2), (1, 3), (3, 3), (3, 1), (2, 1), (2, 3), (2, 2), (1, 1)])
set([(1, 3, 2), (1, 3, 1), (3, 3, 1), (2, 3, 1), (3, 3, 3), (2, 3, 2), (3, 3, 2), (2, 3, 3), (3, 2, 2), (3, 1, 3), (3, 2, 3), (3, 1, 2), (1, 2, 1), (3, 1, 1), (3, 2, 1), (1, 2, 2), (1, 2, 3), (1, 1, 1), (2, 1, 2), (2, 2, 3), (2, 1, 3), (2, 2, 2), (2, 2, 1), (2, 1, 1), (1, 1, 2), (1, 1, 3), (1, 3, 3)])

OTHER TIPS

def cartesian(A,n):
    tmp1,tmp2 = [],[[]]
    for k in range(n):
        for i in A:
            tmp1.extend([j+[i] for j in tmp2])
        tmp1,tmp2 = [],tmp1
    return tmp2

[In:1] A = [1,2,3] ; n = 1
[Out:1] [[1], [2], [3]]

[In:2] A = [1,2,3] ; n = 4
[Out:2] [[1, 1, 1], [2, 1, 1], [3, 1, 1], [1, 2, 1], [2, 2, 1], [3, 2, 1], [1, 3, 1], 
[2, 3, 1], [3, 3, 1], [1, 1, 2], [2, 1, 2], [3, 1, 2], [1, 2, 2], [2, 2, 2], 
[3, 2, 2], [1, 3, 2], [2, 3, 2], [3, 3, 2], [1, 1, 3], [2, 1, 3], [3, 1, 3], 
[1, 2, 3], [2, 2, 3], [3, 2, 3], [1, 3, 3], [2, 3, 3], [3, 3, 3]]

I think you're looking for what's called the cartesian power of a set.

I'm not sure why you can't use itertools but I think it should be pointed out with an example for safe measure even if you don't use it.

>>> import itertools
>>> set1 = {'a', 'b'}
>>> list(itertools.product(set1, repeat=0))
[()]
>>> list(itertools.product(set1, repeat=1))
[('a',), ('b',)]
>>> list(itertools.product(set1, repeat=2))
[('a', 'a'), ('a', 'b'), ('b', 'a'), ('b', 'b')]

Recursion comes in handy when you need mimic n number of nested for loops.

def cartesian_power(seq, p):
    if p == 0:
        return [()]
    else:
        result = []
        for x1 in seq:
            for x2 in cartesian_power(seq, p - 1):
                result.append((x1,) + x2)
        return result

>>> cartesian_power([1, 2], 0)
[()]
>>> cartesian_power([1, 2], 1)
[(1,), (2,)]
>>> cartesian_power([1, 2], 2)
[(1, 1), (1, 2), (2, 1), (2, 2)]
>>> 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top