ivanesi
ivanesi

Reputation: 1663

Distribute values based on sum and list of provided values

I need to generate list of values from provided that satisfy this requirements:

Sum of all generated values should be equal of total, only providedValues should be used to get the sum, providedValues and total can be any double.

For example:

total = 1.0
providedValues = [0.5, 0.25]

Values in output list should be randomly distributed, for example output can be: [0.5, 0.25, 0.25], [0.25, 0.5, 0.25] or [0.25, 0.25, 0.5]

In case sum can't be equal total:

total = 1.0
providedValues = [0.3]

algorithm should throw error.

Language for implementation not so matter, I'll try to read any.

Upvotes: 0

Views: 382

Answers (2)

CDJB
CDJB

Reputation: 14536

This algorithm will return all the possible combinations that sum to total.

import itertools
import numpy as np

def find_combination(total, providedValues):
    i = 1
    rv = []
    while True:
        combs = list(itertools.combinations_with_replacement(providedValues,i))
        validCombs = [comb for comb in combs if np.isclose(sum(comb),total)]
        if validCombs:
            rv.extend(validCombs)
        elif not [comb for comb in combs if sum(comb) <= total]:
            return rv
        i += 1

Output:

>>> find_combination(1.0, [0.5, 0.25])
[(0.5, 0.5), (0.5, 0.25, 0.25), (0.25, 0.25, 0.25, 0.25)]
>>> find_combination(1.0, [0.3])
[]

If you want to get all permutations of the results, you can use

>>> set(itertools.permutations((0.5, 0.25, 0.25)))
{(0.25, 0.25, 0.5), (0.25, 0.5, 0.25), (0.5, 0.25, 0.25)}

For example:

>>> set(y for x in find_combination(1.0, [0.5, 0.25]) for y in itertools.permutations(x))
{(0.25, 0.25, 0.25, 0.25),
 (0.25, 0.25, 0.5),
 (0.25, 0.5, 0.25),
 (0.5, 0.25, 0.25),
 (0.5, 0.5)}

Upvotes: 2

Sheng Zhuang
Sheng Zhuang

Reputation: 697

Here is my solution based on there are two values provided, you may want to change it for you need

from itertools import permutations, combinations

def get_scala(x,y,t):
    # get list of scala combinations
    # find a,b that a*x+b*y = total
    scala_list = []
    amax = int(t // x)  # possible max scala for x
    bmax = int(t // y)  # possible max scala for y
    for i in range(1, amax+1):
        for j in range(1, bmax+1):
            if i*x + j*y == t:  # find the scala combination that == total
                scala_list.append((i, j))
    if scala_list:
        return scala_list
    else:
        print("Warning: cannot add up to the total")

def dist(x, y, scala):
    a, b = scala
    # get a base list with a number of x and b number of y [x,x,y,y,y]
    bl = [x]*a + [y]*b
    # get permutations and using set to get rid of duplicate items
    return set(permutations(bl)) 


for l in get_scala(0.3, 0.2, 1):
    for d in dist(0.3, 0.2, l):
        print(d)

the output would look look:

(0.2, 0.3, 0.2, 0.3)
(0.2, 0.2, 0.3, 0.3)
(0.3, 0.2, 0.2, 0.3)
(0.3, 0.2, 0.3, 0.2)
(0.3, 0.3, 0.2, 0.2)
(0.2, 0.3, 0.3, 0.2)

Upvotes: 2

Related Questions