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

JavaScript - generating 6 random percentages that add up to 100 - Stack Overflow

programmeradmin2浏览0评论

I'm looking to generate 6 random percentages that add up to 100 in JavaScript. I don't want the difference between the largest and smallest percentage to be more than say 20%.

What is the most efficient way of doing this?

Many thanks.

I'm looking to generate 6 random percentages that add up to 100 in JavaScript. I don't want the difference between the largest and smallest percentage to be more than say 20%.

What is the most efficient way of doing this?

Many thanks.

Share Improve this question asked Sep 6, 2013 at 16:12 user2743326user2743326 1231 silver badge6 bronze badges 2
  • Integers only? Is zero allowed as a value? Do they have to be unique or can there duplicates? – Niet the Dark Absol Commented Sep 6, 2013 at 16:13
  • Preferably integers only. Zero would not be allowed as a value. Duplicates are allowed. Sorry I wasn't clearer. – user2743326 Commented Sep 6, 2013 at 16:36
Add a ment  | 

4 Answers 4

Reset to default 3

I had a similar problem. One nice thing about this is that not only are the numbers random, but which item the array is the largest is also random because the array has been shuffled.

Otherwise, most of the time the 1st number will be the largest, and the 2nd number will be the 2nd largest etc.

Another nice thing is that this will generate as many segments as you want, and you can have a cap for what the largest segment is. e.g. if you're trying to add up to 100, you won't end up with your first number being 99.9.

var generateProportion = function() {
  var max = 100,
    segmentMax = 60,
    tempResults = [],
    remaining = max,
    segments = 5,
    finalResults = [];

   //create a series of random numbers and push them into an array
  for (var i = 1; i <= segments; i++) {
    var r = Math.random() * segmentMax;
    if (i === segments) {
      // the final segment is just what's left after the other randoms are added up
      r = remaining;
    }
    tempResults.push(r);
    // subtract them from the total
    remaining -= r;
    // no segment can be larger than what's remaining
    segmentMax = remaining;
  }

  //randomly shuffle the array into a new array
  while (tempResults.length > 0) {
    var index = Math.floor(Math.random() * tempResults.length);
    finalResults = finalResults.concat(tempResults.splice(index, 1));
  }
  return finalResults;
}
var proportion = generateProportion();
var total = proportion.reduce( (a,b) => a+b);
console.log(proportion, "=", total);
<script src="https://cdnjs.cloudflare./ajax/libs/d3/3.4.11/d3.min.js"></script>

I had to solve a similar problem. This is how I did it:

const random = (min, max) => {
    return min + Math.random() * (max - min);
};

const randomFill = (amount, min, max) => {
    const arr = [];
    let total = 0;

    // fill an array with random numbers
    for (let i = 0; i < amount; i++) arr.push(random(min, max));

    // add up all the numbers
    for (let i = 0; i < amount; i++) total += arr[i];

    // normalise so numbers add up to 1
    for (let i = 0; i < amount; i++) arr[i] /= total;

    return arr;
};

min and max can be anything. The actual values don't matter much because the total is normalised.

const values = randomFill(6, 0.2, 0.5);
// [0.1549, 0.2023, 0.1681, 0.0981, 0.1621, 0.2141]

Here is a jsfiddle: https://jsfiddle/brunoimbrizi/q3fLp8u5/27/

This is a partial solution:

function get_6_rands() {
    var rands = [], rand, total = 0, normalized_rands = [];
    for (var i = 0; i < 6; i += 1) {
        rand = Math.random();
        rands.push(rand);
        total += rand;
    }
    for (var i = 0; i < 6; i += 1) {
        rand = rands[i] / total;
        normalized_rands.push(rand);
    }
    return normalized_rands;
}

function_is_valid(attempt) {
    return true; // implement `is_valid` yourself
}
do {
    var attempt = get_6_rands();
} while (is_valid(attempt) === false);
console.log(attempt); // success!

The function will generate 6 random numbers that, together, are 1. It's achieved through normalization. If you want integers (rather than floats) you will need to do something clever, just rounding isn't enough.

You can get the 20% requirement by checking the requirement, if it fails, try again, and keep trying till you get one that satisfies your requirement. You should get one eventually, it's random after all.

First you make an array of random number between 100 and 120 like that :

var arPercentages = [];

for(var i = 0; i < 6; i++) {
    arPercentages.push(Math.random()*20 + 100);
}

Then you add all the numbers. Choose your method, I always user underscore so I would map(). But basically, what you have to do is something like that :

var total = arPercentages[0] + arPercentages[1] + arPercentages[2] + arPercentages[3] + arPercentages[4] + arPercentages[5];

And finally you just divide and multiply for each number :

for (var i = 0; i < 6; i++) {
    arPercentages[i] = arPercentages[i] / total * 100;
}

You have an array with 6 percentages that add to 100 and that are between 100 and 120% of a base value (but this is very close)

发布评论

评论列表(0)

  1. 暂无评论