Reputation: 944
So using the itertools module I'm able to code up a really slick bit of code for producing all permutations with replacement, but what I wanted to do was something using recursion.
Here's what I came up with:
def permutations_with_replacement(n,k,permutations):
m = 0
if k < 1:
return permutations
for i in range(27):
permutations[i].append(m % n)
if (i % n**(k-1)) == n**(k-1) - 1:
m = m + 1
return permutations_with_replacement(n,k-1,permutations)
n = 3
k = 3
permutations = [[] for i in range(n**k)]
print permutations_with_replacement(n,k,permutations)
Basically it sort of lays the first layer (entry) of each permutation, and then upon each subsequent iteration it runs through 0...n-1 quicker and quicker in order to get all combinations. I put in an example with n=k=3 since I have to initialize the permutations list and initializing it inside the function causes things to get screwed up upon recursion. I also put in 27 for the range rather than n^k, since n^k would get screwed up as well upon recursion. How could this be made to work cleanly?
What I really wanted to do was do a recursion that basically replaced the nested for-loop method of producing all permutations with replacement, my understanding being that recursion gets around the problem that the nested for-loop method requires knowing the depth of the nested for-loops a priori. So if anyone can show me how to do it that way, that would be great as well, thanks.
Upvotes: 0
Views: 1469
Reputation: 14685
I think that the problem with your approach is that you had not committed, mentally to the recursion. Warning signs are having to create the whole sized array before you start, and finding that you need to know how big the whole thing is inside the body of routine recursive routine.
I came up with the following by thinking:
1) What will the answer of p_w_r be for k=1 and any n? I experimented on paper with n=2
2) Given that thing I think is the answer to 1, how do I make the answer for k=2 starting from the output of k=1.
I had to mess around a bit conceptually before I realised that the answer for k=1 has to be a list of single element lists itself (obvious when you see it, of course). From there, I could see that I needed to "stick this list" onto each element in the k+1 case.
def permutations_with_replacement(k,n):
# special case (not part of recursion)
if k == 0:
return []
if k == 1
return [[i] for i in range(n)]
else:
# Make the list by sticking the k-1 permutations onto each number
# we can select here at level k
result = []
# Only call the k-1 case once, though we need it's output n times.
k_take_one_permutations = permutations_with_replacement(k-1,n)
for i in range(n):
for permutation in k_take_one_permutations:
result.append([i]+permutation)
return result
print permutations_with_replacement(3,2)
momerath:~ mgregory$ python foo.py
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
momerath:~ mgregory$
Upvotes: 2
Reputation: 10360
I guess this doesn't help if you want to roll your own solution, but there's a very clean way to do this using itertools.product
, which basically is equivalent to a Cartesian product.
import itertools
def permutations_with_replacement(n, k):
# if you're on Python 2.x, use xrange(n) instead of range(n)
return itertools.product(range(n), repeat=k)
n, k = 3, 3
for permutation in permutations_with_replacement(n, k):
print(permutation)
Output:
(0, 0, 0)
(0, 0, 1)
(0, 0, 2)
(0, 1, 0)
(0, 1, 1)
# some omitted
(2, 1, 1)
(2, 1, 2)
(2, 2, 0)
(2, 2, 1)
(2, 2, 2)
Upvotes: 1