The objective is to obtain distribution lists that allow, for example, to test scenarios by weighting variables with different familiar weights whose sum is equal to 100 (and therefore assimilable to percentages).
The method I propose below works but may not be the best. Feel free to suggest any improvement.
Function for integer compositions into n parts:
def comppercents(n):
y = [0] * n
y[0] = 100
while True:
yield(y)
v = y[-1]
if (100 ==v ):
break
y[-1] = 0
j = -2
while (0==y[j]):
j -= 1
y[j] -= 10
y[j+1] = 10 + v
for x in comppercents(3):
print(x)
[100, 0, 0]
[90, 10, 0]
[90, 0, 10]
[80, 20, 0]
...
[0, 20, 80]
[0, 10, 90]
[0, 0, 100]
(66 variants)
from itertools import groupby
def comb_100(n):
global L_combination_100
L_combination_100= []
# adds in L_combination_100 all the possible lists (without the order mattering) whose sum of the elements is 10
find_raw_combination([i+1 for i in list(range(10))]*10,10)
# we remove all duplicate lists
for i in range(len(L_combination_100)):
L_combination_100[i].sort()
L_combination_100.sort()
L_combination_100 = list(k for k,_ in groupby(L_combination_100)) # groupby from itertools
# We remove all lists that have too many elements (> n)
L_combination_100 = [i if len(i)<=n else [] for i in L_combination_100]
L_combination_100 = [x for x in L_combination_100 if x != []]
# We add 0's to lists that don't have n items
# All items within each list are multiplied by 10 to obtain a sum equal to 100
for i,l in enumerate(L_combination_100) :
if len(l) != n:
L_combination_100[i].extend([0]*(n-len(l)))
L_combination_100[i] = [ii*10 for ii in L_combination_100[i]]
#That's how we got our final list of lists/combinations. We have to be careful that the order doesn't matter in these lists.
return L_combination_100
#Strongly inspired from https://stackoverflow.com/questions/4632322/finding-all-possible-combinations-of-numbers-to-reach-a-given-sum
def find_raw_combination(numbers, target, partial=[]): # need global variable L_combination_100
s = sum(partial)
# check if the partial sum is equals to target
if s == target:
L_combination_100.append(partial) if partial not in L_combination_100 else L_combination_100
if s >= target:
return # reach if we get the number
for i in range(len(numbers)):
n = numbers[i]
remaining = numbers[i+1:]
find_raw_combination(remaining, target, partial + [n])
Example:
comb_100(3)
Output:
[[10, 10, 80],
[10, 20, 70],
[10, 30, 60],
[10, 40, 50],
[10, 90, 0],
[20, 20, 60],
[20, 30, 50],
[20, 40, 40],
[20, 80, 0],
[30, 30, 40],
[30, 70, 0],
[40, 60, 0],
[50, 50, 0],
[100, 0, 0]]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.