最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

arrays - How to divide number n in javascript into x parts, where the sum of all the parts equals the number? - Stack Overflow

programmeradmin3浏览0评论

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
Add a comment  | 

7 Answers 7

Reset to default 6

let 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

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论