I'm trying to find or develop Integer Partitioning code for Python.
FYI, Integer Partitioning is representing a given integer n as a sum of integers smaller than n. For example, an integer 5 can be expressed as 4 + 1 = 3 + 2 = 3 + 1 + 1 = 2 + 2 + 1 = 2 + 1 + 1 + 1 = 1 + 1 + 1 + 1 + 1
I've found a number of solutions for this. http://homepages.ed.ac.uk/jkellehe/partitions.php and http://code.activestate.com/recipes/218332-generator-for-integer-partitions/
However, what I really want is to restrict the number of partitions.
Say, # of partition k = 2, a program only need to show 5 = 4 + 1 = 3 + 2,
if k = 3, 5 = 3 + 1 + 1 = 2 + 2 + 1
I've written a generator solution
def partitionfunc(n,k,l=1):
'''n is the integer to partition, k is the length of partitions, l is the min partition element size'''
if k < 1:
raise StopIteration
if k == 1:
if n >= l:
yield (n,)
raise StopIteration
for i in range(l,n+1):
for result in partitionfunc(n-i,k-1,i):
yield (i,)+result
This generates all the partitions of n with length k with each one being in order of least to greatest.
Just a quick note: Via cProfile, it appears that using the generator method is much faster than using falsetru's direct method, using the test function lambda x,y: list(partitionfunc(x,y)). On a test run of n=50,k-5, my code ran in .019 seconds vs the 2.612 seconds of the direct method.
def part(n, k):
def _part(n, k, pre):
if n <= 0:
return []
if k == 1:
if n <= pre:
return [[n]]
return []
ret = []
for i in range(min(pre, n), 0, -1):
ret += [[i] + sub for sub in _part(n-i, k-1, i)]
return ret
return _part(n, k, n)
Example:
>>> part(5, 1)
[[5]]
>>> part(5, 2)
[[4, 1], [3, 2]]
>>> part(5, 3)
[[3, 1, 1], [2, 2, 1]]
>>> part(5, 4)
[[2, 1, 1, 1]]
>>> part(5, 5)
[[1, 1, 1, 1, 1]]
>>> part(6, 3)
[[4, 1, 1], [3, 2, 1], [2, 2, 2]]
UPDATE
Using memoization:
def part(n, k):
def memoize(f):
cache = [[[None] * n for j in xrange(k)] for i in xrange(n)]
def wrapper(n, k, pre):
if cache[n-1][k-1][pre-1] is None:
cache[n-1][k-1][pre-1] = f(n, k, pre)
return cache[n-1][k-1][pre-1]
return wrapper
#memoize
def _part(n, k, pre):
if n <= 0:
return []
if k == 1:
if n <= pre:
return [(n,)]
return []
ret = []
for i in xrange(min(pre, n), 0, -1):
ret += [(i,) + sub for sub in _part(n-i, k-1, i)]
return ret
return _part(n, k, n)
First I want to thanks everyone for their contribution.
I arrived here needing an algorithm for generating integer partitions with the following details :
Generate partitions of a number into EXACTLY k parts but also having MINIMUM and MAXIMUM constraints.
Therefore, I modified the code of "Snakes and Coffee" to accommodate these new requirements:
def partition_min_max(n, k, l, m):
''' n is the integer to partition, k is the length of partitions,
l is the min partition element size, m is the max partition element size '''
if k < 1:
raise StopIteration
if k == 1:
if n <= m and n>=l :
yield (n,)
raise StopIteration
for i in range(l,m+1):
for result in partition_min_max(n-i, k-1, i, m):
yield result+(i,)
>>> x = list(partition_min_max(20 ,3, 3, 10 ))
>>> print(x)
>>> [(10, 7, 3), (9, 8, 3), (10, 6, 4), (9, 7, 4), (8, 8, 4), (10, 5, 5), (9, 6, 5), (8, 7, 5), (8, 6, 6), (7, 7, 6)]
Building upon previous answer with maximum and minimum constraints, we can optimize it be a little better . For eg with k = 16 , n = 2048 and m = 128 , there is only one such partition which satisfy the constraints(128+128+...+128). But the code searches unnecessary branches for an answer which can be pruned.
def partition_min_max(n,k,l,m):
#n is the integer to partition, k is the length of partitions,
#l is the min partition element size, m is the max partition element size
if k < 1:
return
if k == 1:
if n <= m and n>=l :
yield (n,)
return
if (k*128) < n: #If the current sum is too small to reach n
return
if k*1 > n:#If current sum is too big to reach n
return
for i in range(l,m+1):
for result in partition_min_max(n-i,k-1,i,m):
yield result+(i,)
Related
Wrote a simple code for left array rotation, getting the same array without any Rotation done to it as the wrong output.
def leftRotate(arr, d, n):
while (d-1) > 0:
leftRotatebyOne(arr, n)
def leftRotatebyOne(arr, n):
temp = arr[0]
for i in range(n-1):
arr[i] = arr[i + 1]
arr[n - 1] = temp
def PrintArray(arr, size):
for i in range(size):
print("%d" % arr[i], end=" ")
arr = []
l = int(input("Enter the number of elements: "))
for i in range(0, l):
ele = int(input())
arr.append(ele)
d = int(input("Enter the number of rotations: "))
n = len(arr)
leftRotate(arr, d, n)
PrintArray(arr, n)
and here's an example of the output i've got,
Enter the number of elements: 3
1
2
3
Enter the number of rotations: 1
1 2 3
I expected an output of 2 3 1 after one rotation.
I would suggest using array slicing, then adding the slices together, to perform rotation.
def left_rotate(data, num):
return data[num:] + data[:num]
def right_rotate(data, num):
return data[-num:] + data[:-num]
For example
>>> a = [1,2,3,4,5,6,7]
>>> left_rotate(a, 2)
[3, 4, 5, 6, 7, 1, 2]
>>> right_rotate(a, 2)
[6, 7, 1, 2, 3, 4, 5]
Also note that collections.deque has this behavior available already
>>> from collections import deque
>>> d = deque([1,2,3,4,5,6,7])
>>> d.rotate(2)
>>> d
deque([6, 7, 1, 2, 3, 4, 5])
>>> d.rotate(-2)
>>> d
deque([1, 2, 3, 4, 5, 6, 7])
In the function leftRotate,
there is an error in while loop.
Replace
while (d-1) > 0:
leftRotatebyOne(arr, n)
with
while d > 0:
leftRotatebyOne(arr, n)
d -= 1
When d == 1, while (d-1) > 0: will not be executed any time. Also, you never decrement d. The easiest way to solve is by using a for _ in range(d) loop:
def leftRotate(arr, d, n):
for _ in range(d):
leftRotatebyOne(arr, n)
NOTE: Python has way better ways to do rotations than this. This code seems to be C more than Python. Passing the array length makes no sense in Python for example. And the rotation can be done all in one assignation.
def leftRotate(arr, d):
d %= len(arr)
for _ in range(d):
arr[-1], arr[:-1] = arr[0], arr[1:]
Cory Kramer's answer is even more pythonic. But it has a bug and a difference with your question's methods. The bug is that it doesn't work when the number of rotations requested are higher than the length of the list. The difference is that they are returning a new list instead of modifying it. These two issues could be addresed like this:
def left_rotate(data, num):
num %= len(data)
data[:] = data[num:] + data[:num]
def right_rotate(data, num):
num %= len(data)
data[:] = data[-num:] + data[:-num]
So I have stock = [5,6,8,4,8,3,6,4]. I want to get the index of the greatest element adjacent to the 1st occurrence of the greatest element, 8. So what I want to get will be 6 with index 1. I have tried using this code.
closest = min(range(len(stock)), key=lambda i: abs(stock[i]-max(stock)))
but it just returns the max element.
If I understood your problem correctly, the most interesting input would look like [1,5,8,4,8,7,6,4]. I.e. we need to return the index of the 5 since it's a second maximum closest to the first occurrence of the maximum. If so, then the algorithm would look as follows:
find two leftmost and absolute maximums m1 and m2
if m1 == m2 then the target is in either of two subarrays:
[0, pos(m1))
[pos(m1) + 1, pos(m2))
otherwise, the target is in either of the following subarrays:
[0, pos(m1))
[pos(m1) + 1, len(arr))
We can find k max elements in an array in a close to linear time using the binary heap. So, I think I got a linear solution for you:
import heapq
def nlargest_with_pos(n, arr):
assert len(arr) >= n
largest = heapq.nlargest(n, ((it[1], -it[0]) for it in enumerate(arr)))
return [(it[0], -it[1]) for it in largest]
def find_x(arr):
assert len(arr) > 1
first_max, second_max = nlargest_with_pos(2, arr)
if len(arr) == 2:
return second_max[1]
left_range = (0, first_max[1])
if second_max[0] == first_max[0]:
right_range = (first_max[1] + 1, second_max[1])
else:
right_range = (first_max[1] + 1, len(arr))
left_hand = arr[left_range[0]:left_range[1]]
right_hand = arr[right_range[0]:right_range[1]]
if not left_hand:
return nlargest_with_pos(1, right_hand)[0][1]
if not right_hand:
return nlargest_with_pos(1, left_hand)[0][1]
left_second_max = nlargest_with_pos(1, left_hand)[0]
right_second_max = nlargest_with_pos(1, right_hand)[0]
if left_second_max[0] >= right_second_max[0]:
return left_second_max[1]
else:
return right_second_max[1]
print(find_x([1,5,8,4,8,7,6,4]))
Like this:
stock = [5,6,8,7,8,3,6,4]
if stock.index(max(stock)) == len(stock)-1:
print(len(stock)-2)
elif not stock.index(max(stock)):
print(1)
elif stock[stock.index(max(stock))-1] > stock[stock.index(max(stock))+1]:
print(stock.index(max(stock))-1)
else:
print(stock.index(max(stock))+1)
Output:
1
Not very elegant but this should work nonetheless:
stock.index(max(stock[stock.index(max(stock)) - 1], stock[(stock.index(max(stock)) + 1) % len(stock)]))
You'll have to add handling if there's a chance you see a list with less than three values
This prints index of highest element that's next to the first occurrence of maximum value in list stock:
stock = [1,5,8,4,8,7,6,4]
idx_max = stock.index(max(stock))
print(max([i for i in [idx_max-1, idx_max+1] if -1 < i < len(stock)], key=lambda k: stock[k]))
Prints:
1
Test cases:
stock = [8,3,8,4,8,3,6,4] # 1
stock = [1,3,1,3,8,5,6,4] # 5
stock = [1,3,1,4,1,3,6,8] # 6
stock = [1,5,8,4,8,7,6,4] # 1
Here's one way:
def get_max_neighbour(l):
_max = max(l)
excl = (-1, len(l))
neighbour = max(
(
(l[j], j)
for i in range(excl[-1])
for j in (i-1, i+1)
if l[i] == _max and j not in excl
),
key=lambda x: x[0]
)
return neighbour[1]
Result:
1
The nice thing about this is you can return both the value and index if you want.
Here's my solution to this puzzle. I'd say it is most similar to the solution of #DavidBuck, in that [8] -> -1 and [] -> None, but has four fewer exit points:
from math import inf
def index_of_max_neighbor_of_max(array):
if not array:
return None
index = array.index(max(array))
a = array[index - 1] if index - 1 >= 0 else -inf
b = array[index + 1] if index + 1 < len(array) else -inf
return index + (b > a) * 2 - 1
And my test code:
if __name__ == "__main__":
iomnom = index_of_max_neighbor_of_max
print(iomnom([5, 6, 8, 4, 8, 3, 6, 4])) # 1
print(iomnom([5, 6, 8, 4, 8, 3, 6, 9])) # 6
print(iomnom([5, 3])) # 1
print(iomnom([3, 5])) # 0
print(iomnom([8])) # -1
print(iomnom([])) # None
print(iomnom([5, 6, 8, 7, 8, 3, 6, 4])) # 3
print(iomnom([5, 6, 8, 4, 8, 3, 6, 9])) # 6
print(iomnom([5, 4, 8, 6, 8, 3, 6, 4])) # 3
def max_neighbor_index(l: list):
max_number = max(l)
max_number_indexes = [x for x in range(0, len(l)) if l[x] == max_number]
result = []
for number_index in max_number_indexes:
if number_index == 0:
result.append(1)
elif number_index == len(l) - 1:
result.append(len(l) - 2)
else:
result.append(l.index(max([l[number_index - 1], l[number_index + 1]])))
max_neighbor = max([l[x] for x in result])
return [x for x in result if l[x] == max_neighbor][0]
stock = [5, 6, 8, 4, 8, 3, 6, 4]
print(max_neighbor_index(stock))
1
stock = [5,6,8,4,8,3,6,4]
idx = 1
tmp,nxt = stock[0:2]
for i in range(1, len(stock)):
buf = stock[i-1] if i == len(stock)-1 else max(stock[i-1], stock[i+1])
if tmp < stock[i] or (tmp == stock[i] and nxt < buf):
idx = stock.index(buf, i-1)
nxt = stock[idx]
tmp = stock[i]
print('greatest next to greatest', nxt, 'at', idx)
Not very pretty, but it will cater for all possible scenarios, i.e. your list, max value a the start or the end, two or one value list.
Code is:
def highest_neighbour(stock):
if stock:
x = stock.index(max(stock))
if x - 1 >= 0:
if x + 1 < len(stock):
if stock[x + 1] > stock[x - 1]:
return x + 1
return x - 1
elif x + 1 < len(stock):
return x + 1
else:
return -1
I've set it to return -1 if the list only has one entry.
Output is:
highest_neighbour([5,6,8,4,8,3,6,4]) # -> 1
highest_neighbour([5,6,8,4,8,3,6,9]) # -> 6
highest_neighbour([9,6,8,4,8,3,6,4]) # -> 1
highest_neighbour([3,5]) # -> 0
highest_neighbour([8]) # -> -1
highest_neighbour([]) # -> None
I need to print out n indexes of elements of list that after multiplying equal to some given integer. It's guaranteed that the combination exists in a list. For example, for the following input(number of elements in array, multiplication wanted number, number of elements in wanted sublist and given array):
7 60 4
30 1 1 3 10 6 4
I should get in any order
1 2 4 5
Because 1*1*10*6==60. If there are more than 1 solution I need to print any of them.
My solution works but pretty slow, how can I make it work faster?
from itertools import chain, combinations
arr = list(map(int, input().split()))
numbers = list(map(int, input().split()))
s = sorted(numbers)
def filtered_sublists(input_list, length):
return (
l for l in all_sublists(input_list)
if len(l) == length
)
def all_sublists(l):
return chain(*(combinations(l, i) for i in range(len(l) + 1)))
def multiply(arr):
result = 1
for x in arr:
result = result * x
return result
def get_indexes(data):
indexes = []
for i in range(len(data)):
if arr[1] == multiply(data[i]):
for el in data[i]:
if numbers.index(el) in indexes:
all_ind = [i for i, x in enumerate(numbers) if x == el]
for ind in all_ind:
if ind not in indexes:
indexes.append(ind)
break
else:
indexes.append(numbers.index(el))
break
return indexes
sublists = list(filtered_sublists(numbers, arr[2]))
print(*get_indexes(sublists))
The key is don't test every combination.
def combo(l, n=4, target=60, current_indices=[], current_mul=1):
if current_mul > target and target > 0:
return
elif len(current_indices) == n and current_mul == target:
yield current_indices
return
for i, val in enumerate(l):
if (not current_indices) or (i > current_indices[-1] and val * current_mul <= target):
yield from combo(l, n, target, current_indices + [i], val * current_mul)
l = [30,1,1,3,10,6,4]
for indices in combo(l, n=4, target=60):
print(*indices)
Prints:
1 2 4 5
More testcases:
l = [1,1,1,2,3,3,9]
for c, indices in combo(l, n=4, target=9):
print(*indices)
Prints:
0 1 2 6
0 1 4 5
0 2 4 5
1 2 4 5
We can use a memoized recursion for an O(n * k * num_factors), solution, where num_factors depends on how many factors of the target product we can create. The recurrence should be fairly clear from the code. (Zeros aren't handled but those should be pretty simple to add extra handling for.)
Pythonesque JavaScript code:
function f(A, prod, k, i=0, map={}){
if (i == A.length || k == 0)
return []
if (map[[prod, k]])
return map[[prod, k]]
if (prod == A[i] && k == 1)
return [i]
if (prod % A[i] == 0){
const factors = f(A, prod / A[i], k - 1, i + 1, map)
if (factors.length){
map[[prod, k]] = [i].concat(factors)
return map[[prod, k]]
}
}
return f(A, prod, k, i + 1, map)
}
var A = [30, 1, 1, 3, 10, 6, 4]
console.log(JSON.stringify(f(A, 60, 4)))
console.log(JSON.stringify(f(A, 60, 3)))
console.log(JSON.stringify(f(A, 60, 1)))
You could start from the target product and recursively divide by factors in the remaining list until you get down to 1 and after using the specified number of factors. This has the advantage of quickly eliminating whole branches of recursion under numbers that are not a factor of the target product.
Handling zero values in the list and a target product of zero requires a couple of special conditions at the start and while traversing factors.
For example:
def findFactors(product, count, factors, offset=0):
if product == 0: return sorted((factors.index(0)+i)%len(factors) for i in range(count))
if not count: return [] if product == 1 else None
if not factors: return None
for i,factor in enumerate(factors,1):
if factor == 0 or product%factor != 0: continue
subProd = findFactors(product//factor,count-1,factors[i:],i+offset)
if subProd is not None: return [i+offset-1]+subProd
r = findFactors(60, 4, [30,1,1,3,10,6,4])
print(r) # [1, 2, 4, 5]
r = findFactors(60, 4, [30,1,1,0,3,10,6,4])
print(r) # [1, 2, 5, 6]
r = findFactors(0, 4, [30,1,1,3,10,6,0,4])
print(r) # [0, 1, 6, 7]
I recently tried the question for the highest product of 3 elements. Now I am trying to do it for the k elements. Let's say from 3 now it is asking for 4 elements. I tried to write a generic function so it could handle for any k elements within the array. The algo has to be in O(n) just like the one with 3 elements is.
def highest_product_sol(input):
high = max(input[0],input[1])
low = min(input[0],input[1])
max_prod_2 = input[0] * input[1]
low_prod_2 = input[0] * input[1]
max_prod_3 = max_prod_2 * input[2]
prod_2_high = input[0] * input[1]
prod_2_low = input[0] * input[1]
for i in range(2,len(input)):
val = input[i]
max_prod_3 = max(max_prod_3,max_prod_2*val,low_prod_2*val)
prod_2_high = high * val
prod_2_low = low * val
max_prod_2 = max(max_prod_2,prod_2_high)
low_prod_2 = min(low_prod_2,prod_2_high)
high = max(high,val)
low = min(low,val)
return (max_prod_2,low_prod_2,max_prod_3)
def highest_product_num(input,num):
high = max(input[0:num - 1])
low = min(input[0:num - 1])
print("max",high)
print("min",low)
prod_high_minus_1 = 1
prod_low_minus_1 = 1
for n in range(0,num-1):
prod_high_minus_1 *= input[n]
prod_low_minus_1 *= input[n]
max_prod_n_1 = prod_high_minus_1
min_prod_n_1 = prod_high_minus_1
max_prod_n = prod_high_minus_1 * input[num-1]
for i in range(num,len(input)):
val = input[i]
max_prod_n = max(max_prod_n,max_prod_n_1*val,min_prod_n_1*val)
prod_high_minus_1 = high * val
prod_low_minus_1 = low * val
max_prod_n_1 = max(max_prod_n_1,prod_high_minus_1)
min_prod_n_1 = min(min_prod_n_1,prod_low_minus_1)
high = max(high,val)
low = min(low,val)
return max_prod_n
test_input = [[1,2,3,4,5,6,7,8],[1,-2,3,4,5,100,2,3,1],[-10,-10,1,3,2][1000,7,-6,2,2]]
print(test_input)
for i in test_input:
print(highest_product_num(i,4),"\n")
# correct `results`
# 1680
# 6000
# 600
O(n) solution in numpy, stress-tested on the 4 example lists and #Stefan Pochmann's merciless auto test script. Big thanks to Stefan, without whose input a couple of severe bugs would have gone unnoticed.
import numpy as np
def kmaxprod_v2(data, k):
if len(data) < k:
return np.nan
data = np.asanyarray(data)
# for integer dtypes convert to python ints to have unlimited range for the
# final product
dfp = data.astype(object) if data.dtype in (
int, np.int64, np.int32, np.int16, np.int8) else data
# np.argpartition raises an exception if len(data) == k, therefore
if len(data) == k:
return np.prod(dfp)
neg = data <= 0
# if k is odd and there are no positive elements we must settle for the
# least negative
if k % 2 == 1 and np.count_nonzero(neg) == len(data):
return np.prod(-np.partition(-data, k)[:k].astype(dfp.dtype))
# now n > k and we have at least one positive element
ap = np.argpartition(-np.absolute(data), k)
low, high = ap[k:], ap[:k]
# try multiplying the k with highest absolute value
greedy = np.prod(dfp[high])
if greedy >= 0:
return greedy
# there are two possible ways of fixing the sign:
# either swap the worst negative inside for the best positive outside
# or swap the worst positive inside for the best negative outside
# compute both and compare
# bpo in, wni out
bpo = np.max(dfp[low])
if bpo <= 0:
spfn = 0
else:
neg_high = np.where(neg[high])[0]
wni_ind = np.argmax(data[high[neg_high]])
# translate to index in high
wni_ind = neg_high[wni_ind]
spfn = bpo*np.prod(dfp[high[:wni_ind]])*np.prod(dfp[high[wni_ind+1:]])
# bno in, wno out
pos_high = np.where(~neg[high])[0]
if len(pos_high) == 0:
snfp = 0
else:
wpi_ind = np.argmin(data[high[pos_high]])
wpi_ind = pos_high[wpi_ind]
bno = np.min(dfp[low])
snfp = bno*np.prod(dfp[high[:wpi_ind]])*np.prod(dfp[high[wpi_ind+1:]])
return max(spfn, snfp)
Brief description of algo:
special case k odd, all data negative find k least negative by partition, return prod, stop
partition by absolute value, splitting at rank k - O(n) worstcase with introselect library function
if prod top k >= 0, stop
if possible swap least positive inside for most negative outside, store prod
if possible swap least negative inside for most positive outside, store prod
return best of above, stop
Sample run:
>>> test_input = [[1,2,3,4,5,6,7,8],[1,-2,3,4,5,100,2,3,1],[-10,-10,1,3,2],[1000,7,-6,2,2]]
>>> for t in test_input:
... kmp.kmaxprod(t,4)
...
1680
6000
600
28000
Test script, thanks #Stefan Pochmann
import itertools, operator, functools, time
def naive(data, k):
return max(functools.reduce(operator.mul, comb) for comb in itertools.combinations(data, k))
test_input = [([1,2,3,4,5,6,7,8], 4), ([1,-2,3,4,5,100,2,3,1], 4),
([-10,-10,1,3,2], 4), ([1000,7,-6,2,2],4),
([-1, 0, 1], 2), ([2, 5, 8, 9, 1, 3, 7], 4),
([-1, -1, 2, 1], 2), ([-1000, -1, 2, 3], 2),
([3, 5, 2, 8, 3], 2), ([-1000, -1, 2, 3, 4, 5, 6, 7], 2)]
for t, k in test_input:
print(t, k, kmaxprod_v2(t, k), naive(t, k))
ne = 0
t = np.zeros((3,))
import random
for k in range(2, 20):
for n in range(k, 24):
print('n =', n, ': k =', k, 'errors:', ne, 'total time O(n), naive:', np.diff(t))
for _ in range(100):
data = [random.randrange(-14, 15) for _ in range(n)]
t[0] += time.time()
a = kmaxprod_v2(data, k)
t[1] += time.time()
b = naive(data, k)
t[2] += time.time()
if a != b:
ne += 1
print(data, k, a, b)
from functools import reduce
import operator
def get_largest_product(l,n):
possible_products = [reduce(operator.mul,c,1) for c in combinations(l, n)]
return max(possible_products)
print (get_largest_product([232,434,5,4],3))
Output:
503440
I wanted to generate all permutations from the list of integers [3,5,7,9] which resulted in a specific sum value 15. I implemented this, it's OK.
def add_next(seq, count, m):
s = sum(seq)
if s == m:
count += 1
print(seq)
elif s < m:
for i in [3,5,7,9]:
add_next(seq + [i], count, m)
else:
return count
add_next([], 0, 15)
Output:
[3, 3, 3, 3, 3]
[3, 3, 9]
[3, 5, 7]
[3, 7, 5]
[3, 9, 3]
[5, 3, 7]
[5, 5, 5]
[5, 7, 3]
[7, 3, 5]
[7, 5, 3]
[9, 3, 3]
The problem is how to re-write this function to return just the number of possible permutations as a function result? Since for huge lists and big sum values it's not reasonable to generate all string outputs. I don't fully understand how to pass values inside and outside recursive function.
I tried:
def add_next2(seq, count, m):
s = sum(seq)
if s == m:
count += 1
print(seq)
elif s < m:
for i in [3,5,7,9]:
count = add_next2(seq + [i], count, m)
else:
return count
add_next([], 0, 15)
but it retuns an error TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int'. So count is None. Why?
Another option is how to re-write this function to transform it to the generator and yield the output strings one after another?
If you're just counting successful recursive results, you don't need 'count' as a parameter. You can just return the successful results as 1 and unsuccessful as 0, letting them accumulate.
EDIT 2 A little more concise but still readable
def add_next(seq, m):
s = sum(seq)
count = 1 if s == m else 0
if s < m:
for i in [f for f in [3,5,7,9] if s + f <= m]:
count += add_next(seq + [i], m)
return count
print(add_next([], 15))
EDIT You can also filter your [3,5,7,9] list so that your for i in loop only deals with elements that have a possibility of success.
for i in [f for f in [3,5,7,9] if s + f <= m]:
Your recursive function doesn't return a value for s <= m. Return something from your function for those cases, otherwise None is returned instead.
Most likely you want to return count in all cases:
def add_next2(seq, count, m):
s = sum(seq)
if s == m:
count += 1
elif s < m:
for i in [3,5,7,9]:
count = add_next2(seq + [i], count, m)
return count
This then works:
>>> def add_next2(seq, count, m):
... s = sum(seq)
... if s == m:
... count += 1
... elif s < m:
... for i in [3,5,7,9]:
... count = add_next2(seq + [i], count, m)
... return count
...
>>> add_next2([], 0, 15)
11