Skip to content
Advertisement

Python: generate 5 random int (every has own range) with fixed sum

import random
#lets take kg(for Total) for better understanding

Total = random.randint(40, 110) #For example Total=100   kg and this is 100%%

Total = (a+b+c+d+e) 
 

Each value in Total has own range (in %).

First: find random values (within ranges that is % from Total.).

I tried this (but sum() can be >or< than 100):

a=random.randint(40, 70)

b=random.randint(0, 4)

c=random.randint(0, 2)

d=random.randint(22, 44)

e=random.randint(0, 7)

Second:find exact value for a,b,c,d,e (according to the percentage from Total in First part). I tried this:

a=Total*random.randint(40, 70)/100

b=Total*random.randint(0, 4)/100

c=Total*random.randint(0, 2)/100

d=Total*random.randint(22, 44)/100

e=Total*random.randint(0, 7)/100

This code does not work. please help

Advertisement

Answer

I’d start with the smallest ranges first, then pick the last one not randomly but as the difference between the sum of the other 4 and 100. Since random numbers can’t be guaranteed to meet all the constraints, you may need to keep picking until you get a satisfactory answer.

def sum_to_100(range_list):
    if sum(lo for lo,hi in range_list) > 100 or sum(hi for lo,hi in range_list) < 100:
        raise ValueError('Solution is impossible within the constraints')
    ordered_ranges = sorted((lo,hi,i) for i,(lo,hi) in enumerate(range_list))
    n = len(range_list)
    solution = []
    while len(solution) != n or sum(solution) != 100:
        index = len(solution)
        lo, hi, i = ordered_ranges[index]
        if index == n - 1:
            final = 100 - sum(solution)
            if lo <= final <= hi:
                solution.append(final)
            else:  # start over
                solution = []
        else:
            solution.append(random.randint(lo, hi))
    # restore the original order
    solution = [num for i,num in sorted(enumerate(solution), key=lambda x:ordered_ranges[x[0]][2])]
    return solution

>>> sum_to_100([(40, 70), (0, 4), (0, 2), (22, 44), (0, 7)])
[59, 3, 1, 32, 5]
>>> sum_to_100([(40, 70), (0, 4), (0, 2), (22, 44), (0, 7)])
[47, 2, 0, 44, 7]

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement