'Recursivly looping through vectors with generators in Python
The following python-code uses recursion to print all lists of nonnegative integers of length 3 whose sum is 2, it works as intended:
def rek(f,sum,n,vector=[]): #applies f to all Z^n_+ vectors of sum 'sum' if n==1: f(vector+[sum]) else: for i in range(sum+1): rek(f,sum-i,n-1,vector+[i]) rek(print,2,3)
Output:
[0, 0, 2] [0, 1, 1] [0, 2, 0] [1, 0, 1] [1, 1, 0] [2, 0, 0]
My question is if and how I could do this with generators instead? I would like to be able to write something like
for vector in vector_generator(2,3): print(vector)
to print the same vectors.
Solution 1:[1]
You should look into yield and yield from, here's how you'd do it:
def vector_generator(sum, n, vector=()):
if n == 1:
yield vector + (sum,)
else:
for i in range(sum + 1):
yield from vector_generator(sum - i, n - 1, vector + (i,))
Note that I changed vector to a tuple, as giving a mutable object as a default argument is not good practice (editing the value will change the default argument).
Solution 2:[2]
You can convert your function to a generator in a simple fashion:
def vector_generator(sum,n,vector=None):
vector = vector or []
if n==1:
yield vector+[sum]
else:
for i in range(sum+1):
yield from vector_generator(sum-i,n-1,vector+[i])
for vector in vector_generator(2,3):
print(vector)
Solution 3:[3]
def gen(s,n):
nums = [0 for _ in range(n)]
while True:
if sum(nums) == s:
yield nums.copy()
cidx = 0
nums[cidx] += 1
while nums[cidx] == s+1:
nums[cidx] = 0
cidx += 1
if cidx == n:
return
nums[cidx] += 1
for vector in gen(2,3):
print(vector)
Not the most optimal solution but it should give correct results. What it does is basicly iterate over all the possible arrays of length n with numbers [0-s] and yields the ones that sum to s.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Peter |
| Solution 2 | Bharel |
| Solution 3 | matszwecja |
