For example I would like to generate 22 numbers between 20 and 46 with an average value of 27. And I would like the numbers to cover the range as well as possible.
E
You could sove this in a pure mathematical way.
if the amount of needed numbers is no even - just select one of the numbers as the average itself and then you will need to generate k-1 numbers (which is even)
** EDIT **
you can use this code that manipulates an initial list to meet the requirements of a average so the resulting list is not symmetrical. (Better than generating lists until you hit the correct one)
import random
def generate_numbers(wanted_avg, numbers_to_generate, start, end):
rng = [i for i in range(start, end)]
initial_selection = [random.choice(rng) for _ in range(numbers_to_generate)]
initial_avg = reduce(lambda x, y: x+y, initial_selection) / float(numbers_to_generate)
print "initial selection is: " + str(initial_selection)
print "initial avg is: " + str(initial_avg)
if initial_avg == wanted_avg:
return initial_selection
off = abs(initial_avg - wanted_avg)
manipulation = off * numbers_to_generate
sign = -1 if initial_avg > wanted_avg else 1
manipulation_action = dict()
acceptable_indices = range(numbers_to_generate)
while manipulation > 0:
random_index = random.choice(acceptable_indices)
factor = manipulation_action[random_index] if random_index in manipulation_action else 0
after_manipulation = initial_selection[random_index] + factor + sign * 1
if start <= after_manipulation <= end:
if random_index in manipulation_action:
manipulation_action[random_index] += sign * 1
manipulation -= 1
else:
manipulation_action[random_index] = sign * 1
manipulation -= 1
else:
acceptable_indices.remove(random_index)
for key in manipulation_action:
initial_selection[key] += manipulation_action[key]
print "after manipulation selection is: " + str(initial_selection)
print "after manipulation avg is: " + str(reduce(lambda x, y: x+y, initial_selection) / float(numbers_to_generate))
return initial_selection