Split number into 4 random numbers

前端 未结 7 811
-上瘾入骨i
-上瘾入骨i 2020-12-30 08:11

I want to split 10 into an array of 4 random numbers, but neither can be 0 or higher than 4. For example [1,2,3,4],

7条回答
  •  一生所求
    2020-12-30 08:42

    The simplest solution is brute force.

    1. Make a while loop to nest your calculations in
    2. In the loop, create an empty array and fill it with random values until length is reached
    3. Check if the sum of the array is your desired value, and if it is then break the loop

    The above should run until you have a result.

    Two things worth considering though.

    1. Your can easily test if a solution is at all possible by calculating, that length-of-array times minimum-value isn't more than the sum and length-of-array times maximum-value isn't less than the sum.
    2. A loop based on random conditions could potentially run forever, so a maximum amount of iterations might be desirable.

    Both of these points are considered in the snippet below:

    function randomNumber(max, min) {
      while (true) {
        var r = Math.round(Math.random() * max);
        if (r >= min) {
          return r;
        }
      }
    }
    
    function splitXintoYComponentsBetweenMaxAndMin(numberToSplit, numberOfSplits, maxValue, minValue, onUpdate) {
      if (minValue === void 0) {
        minValue = 1;
      }
      //Test that a result can exist
      if (maxValue * numberOfSplits < numberToSplit || minValue * numberOfSplits > numberToSplit) {
        return new Promise(function(resolve, reject) {
          resolve(false);
        });
      }
      //Create returner array
      var arr = [];
      var accumulator = 0;
      while (arr.length < numberOfSplits) {
        var val = randomNumber(Math.floor(numberToSplit / numberOfSplits), minValue);
        accumulator += val;
        arr.push(val);
      }
      return new Promise(function(resolve, reject) {
        function runTest() {
          var d = Date.now();
          var localMaxValue = Math.min(maxValue, Math.ceil((numberToSplit - accumulator) / 4));
          //Combination loop
          while (accumulator < numberToSplit && Date.now() - d < 17) {
            var index = Math.round(Math.random() * (arr.length - 1));
            if (arr[index] >= maxValue) {
              continue;
            }
            var r = randomNumber(localMaxValue, minValue);
            while (arr[index] + r > maxValue || accumulator + r > numberToSplit) {
              if (Date.now() - d >= 17) {
                break;
              }
              r = randomNumber(localMaxValue, minValue);
            }
            if (arr[index] + r > maxValue || accumulator + r > numberToSplit) {
              continue;
            }
            arr[index] += r;
            accumulator += r;
          }
          if (accumulator < numberToSplit) {
            if (onUpdate !== void 0) {
              onUpdate(arr);
            }
            requestAnimationFrame(runTest);
          } else {
            resolve(arr);
          }
        }
        runTest();
      });
    }
    //TEST
    var table = document.body.appendChild(document.createElement('table'));
    table.innerHTML = "Number to splitNumber of splitsMax valueMin valueRun" +
      "";
    var output = document.body.appendChild(document.createElement('pre'));
    output.style.overflowX = "scroll";
    document.getElementById("run").onclick = function() {
      splitXintoYComponentsBetweenMaxAndMin(parseInt(document.getElementById("number-to-split").value, 10), parseInt(document.getElementById("number-of-splits").value, 10), parseInt(document.getElementById("max-value").value, 10), parseInt(document.getElementById("min-value").value, 10))
        .then(function(data) {
          if (data !== false) {
            output.textContent += data.join("\t") + '\n';
          } else {
            output.textContent += 'Invalid data\n';
          }
        });
    };

    EDIT 1 - Big calculations

    Using requestAnimationFrame and Promises the code can now execute asynchronously, which allows for longer calculation time without bothering the user.

    I also made the random function scale with the remaining range, greatly reducing the amount of calculations needed for big numbers.

提交回复
热议问题