This code was created for a game project in which 10 houses need to be populated with 16 people. I wanted the distribution to be random, with no more than 3 and no less than 1 person per house and no remaining people or houses.
function getRandomPartitionsFromNumber(number, parts, min, max) {
var result = [];
for (var i = 0; i < parts; i++) {
var part = randomIntFromInterval(min, max);
result.push(part);
}
var sum = result.reduce(add, 0);
// If the sum is greater than the number, we need to iterate through
// the result and remove some numbers until it's equal
while (sum > number) {
for (i = 0; i < result.length; i++) {
if (result[i] > min) {
result[i]--;
sum = result.reduce(add, 0);
if (sum === number) {
break;
}
}
}
sum = result.reduce(add, 0);
}
while (sum < number) {
for (i = 0; i < result.length; i++) {
if (result[i] < max) {
result[i]++;
sum = result.reduce(add, 0);
if (sum === number) {
break;
}
}
}
}
return result;
}
function randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function randomFromArray(array) {
return array[randomIntFromInterval(0, array.length - 1)];
}
function add(a, b) {
return a + b;
}
console.log(getRandomPartitionsFromNumber(16, 10, 1, 3));
1 Answer 1
The way you have done your algorithm, you could just apply the same operation to your sum
variable, rather than reducing the entire array.
while (sum > number) {
for (i = 0; i < result.length; i++) {
if (result[i] > min) {
result[i]--;
sum--
if (sum === number) {
break;
}
}
}
sum = result.reduce(add, 0);
}
Additionally, the last sum = result.reduce
is not needed here, as any change in the result array is subsequently reflected in the sum variable a row lower.
while (sum > number) {
for (i = 0; i < result.length; i++) {
if (result[i] > min) {
result[i]--;
sum--
if (sum === number) {
break;
}
}
}
}
Lastly, keep in mind if you were to feed your code an impossible situation ("stuff 5 people into 1 house where each house can only contain 3 people at most"), you will get an infinite loop. It's up to you to decide how to handle this.