I have a number which I need to divide into 5 parts. However, I want each part to be a random number. But when all the parts are added together, they equal the original number. I am unsure of how to do this with JavaScript. Furthermore, I don't want the min of the divided parts to be 0 or 1, I want to set the min myself.
For example, the number is 450. I want the divided parts to be no less than 60. So to start, the array would be [60,60,60,60,60]. But I want to randomize so that they all add up to 450. What would be the best way to go about doing this?
Thank you!
This is what I've tried so far:
let i = 0;
let number = 450;
let numArray = [];
while(i <= 5){
while(number > 0) {
let randomNum = Math.round(Math.random() * number) + 1;
numArray.push(randomNum);
number -= randomNum;
}
i += 1;
}
I have a number which I need to divide into 5 parts. However, I want each part to be a random number. But when all the parts are added together, they equal the original number. I am unsure of how to do this with JavaScript. Furthermore, I don't want the min of the divided parts to be 0 or 1, I want to set the min myself.
For example, the number is 450. I want the divided parts to be no less than 60. So to start, the array would be [60,60,60,60,60]. But I want to randomize so that they all add up to 450. What would be the best way to go about doing this?
Thank you!
This is what I've tried so far:
let i = 0;
let number = 450;
let numArray = [];
while(i <= 5){
while(number > 0) {
let randomNum = Math.round(Math.random() * number) + 1;
numArray.push(randomNum);
number -= randomNum;
}
i += 1;
}
Share
Improve this question
edited Aug 12, 2017 at 17:21
cjh193
asked Aug 12, 2017 at 17:08
cjh193cjh193
3592 gold badges4 silver badges9 bronze badges
4
- Did you try anything? – Yogen Darji Commented Aug 12, 2017 at 17:15
- I've tried using a while loop inside of another while loop with the math.round function. I'll update my question with my code. – cjh193 Commented Aug 12, 2017 at 17:16
- 1 This may behelpful stackoverflow.com/a/25306036/6448640 – user6448640 Commented Aug 12, 2017 at 17:17
- Do you want the possible lists of numbers to have uniform probability--each is as likely as another? There are many easy ways to get such lists but they will not have equal probability. That last part is possible but harder. Also, does the order of the five numbers matter? – Rory Daulton Commented Aug 12, 2017 at 17:22
7 Answers
Reset to default 6let your number be N, and let pn be the nth part. To get 5 parts:
- p1 = random number between 0 and N
- p2 = random number between 0 and N - p1
- p3 = random number between 0 and N - p2 - p1
- p4 = random number between 0 and N - p3 - p2 - p1
- p5 = N - p4 - p3 - p2 - p1
Edit 2017
To make it seem more random, shuffle the numbers after you generate them
Edit 2020
I guess some code wouldn't hurt. Using ES7 generators:
function* splitNParts(num, parts) {
let sumParts = 0;
for (let i = 0; i < parts - 1; i++) {
const pn = Math.ceil(Math.random() * (num - sumParts))
yield pn
sumParts += pn
}
yield num - sumParts;
}
Fiddle Link
Sum the five minimums (eg min = 60
) up:
var minSum = 5 * min
Then get the difference between your original number (orNumber = 450
) and minSum
.
var delta = orNumber - minSum
Now you get 4 different random numbers in the range from 0 to exclusive 1.
Sort these numbers ascending.
Foreach of these randoms do the following:
- Subtract it from the last one (or zero for the first)
- Multiply this number with the
delta
and you get one of the parts.
The last part is the delta
minus all other parts.
Afterwards you just have to add your min
to all of the parts.
This function generates random numbers from 0 to 1, adds them together to figure out what they need to be multiplied by to provide the correct range. It has the benefit of all the numbers being fairly distributed.
function divvy(number, parts, min) {
var randombit = number - min * parts;
var out = [];
for (var i=0; i < parts; i++) {
out.push(Math.random());
}
var mult = randombit / out.reduce(function (a,b) {return a+b;});
return out.map(function (el) { return el * mult + min; });
}
var d = divvy(450, 6, 60)
console.log(d);
console.log("sum - " + d.reduce(function(a,b){return a+b}));
You can use a do..while
loop to subtract a minimum number from original number, keep a copy of original number for subtraction at conclusion of loop to push the remainder to the array
let [n, total, m = n] = [450, 0];
const [min, arr] = [60, []];
do {
n -= min; // subtract `min` from `n`
arr.push(n > min ? min : m - total); // push `min` or remainder
total += arr[arr.length - 1]; // keep track of total
} while (n > min);
console.log(arr);
To randomize output at resulting array select a number greater than min
and less than n
to create a random number within a specific range
let [n, total, m = n] = [450, 0];
const [min, arr, range = min + min / 2] = [60, []];
do {
let r = Math.random() * (range - min) + min; // random number in our range
n -= r; // subtract `min` from `n`
arr.push(n > min ? r : m - total); // push `r` or remainder
total += arr[arr.length - 1]; // keep track of total
} while (n > min);
console.log(arr);
The highest rated answer doesn't include the minimum variable, so here are some adjustments that I've made:
function* splitNParts(num, parts, min) {
let remParts = parts;
let sumParts = num;
for (let i = 0; i < parts - 1; i++) {
const pn = Math.ceil(Math.random() * (sumParts - (remParts*min)) + min)
yield pn
sumParts -= pn;
remParts -= 1;
}
yield sumParts;
}
console.log(...splitNParts(450, 5, 60));
I made a longer version for beginners.
const n = 450;
const iterations = 5;
const parts = [];
// we'll use this to store what's left on each iteration
let remainder = n;
for (let i = 1; i <= iterations; i += 1) {
// if it's the last iteration, we should just use whatever
// is left after removing all the other random numbers
// from our 450
if (i === iterations) {
parts.push(remainder);
break;
}
// every time we loop, a random number is created.
// on the first iteration, the remainder is still 450
const part = Math.round(Math.random() * remainder);
parts.push(part);
// we must store how much is left after our random numbers
// are deducted from our 450. we will use the lower number
// to calculate the next random number
remainder -= part;
}
// let's print out the array and the proof it still adds up
const total = totalFromParts(parts);
console.log(parts);
console.log('Total is still ' + total);
// this function loops through each array item, and adds it to the last
// just here to test the result
function totalFromParts(parts) {
return parts.reduce((sum, value) => sum + value, 0);
}
There are much more efficient ways to code this, but in the interest of explaining the logic of solving the problem, this walks through that step by step, transforming the values and explaining the logic.
// Set start number, number of fragments
// minimum fragment size, define fragments array
var n = 450
var x = 5
var minNumber = 60
var fragment = n / x
// stuff array with equal sized fragment values
var fragments = []
for (i = 0; i < x; i++) {
fragments[i] = fragment;
}
document.write("fragments: " + fragments);
var delta = [];
// iterate through fragments array
// get a random number each time between the fragment size
// and the minimum fragment sized defined above
// for even array slots, subtract the value from the fragment
// for odd array slots, add the value to the fragment
// skip the first [0] value
for (i = 1; i< x; i++) {
delta[i] = Math.floor(Math.random() * (fragment - minNumber));
document.write("<br />delta: " + delta[i]);
if((i % 2) == 1) {
fragments[i] -= delta[i]
}
else {
fragments[i] += delta[i]
}
}
// set the initial fragment value to 0
fragments[0] = 0
// defines a function we can use to total the array values
function getSum(total, num) {
return total + num;
}
// get the total of the array values, remembering the first is 0
var partialTotal = fragments.reduce(getSum)
document.write("<br />partial sum: " + partialTotal);
// set the first array value to the difference between
// the total of all the other array values and the original
// number the array was to sum up to
fragments[0] = (n - partialTotal)
// write the values out and profit.
document.write("<br />fragments: " + fragments);
var grandTotal = fragments.reduce(getSum)
document.write("<br />Grand total: " + grandTotal);
https://plnkr.co/edit/oToZe7LGpQS4dIVgYHPi?p=preview