Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Split number into 4 random numbers

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], [1,4,4,1] or [4,2,3,1].

I think it's an easy question, but for some reason I can't think of how to do this. If someone has some instruction that would be very helpful!

Edit: This is the code I have now, but I generates also a total number under 10:

  let formation = [];
  let total = 0;

   for (let i = 0; i < 4; i ++) {
    if (total < 9) {
      formation[i] = Math.floor(Math.random() * 4) + 1; 
    } else {
      formation[i] = 1;
    }
  }
like image 331
MikeHrn Avatar asked May 18 '18 06:05

MikeHrn


1 Answers

You could create all possible combinations and pick a random array.

function get4() {

    function iter(temp) {
        return function (v) {
            var t = temp.concat(v);
            if (t.length === 4) {
                if (t.reduce(add) === 10) {
                    result.push(t);
                }
                return;
            }
            values.forEach(iter(t));
        };
    }
    
    const
        add = (a, b) => a + b,
        values = [1, 2, 3, 4],
        result = [];

    values.forEach(iter([]));
    return result;
}

console.log(get4().map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }

An algorithm for getting random values without a list of all possible combinations

It works by using a factor for the random value and an offset, based on the actual sum, index, minimum sum which is needed for the next index, and the maximum sum.

The offset is usually the minimum sum, or the greater value of the difference of sum and maximum sum. For getting the factor, three values are taken for the minimum for multiplying the random value.

The table illustrates all possible values of the sum and the needed iterations, based on a given value and the iteration for getting all values.

At the beginning the sum is the value for distribution in small parts. The result is the second block with a rest sum of 14 ... 10, because it is possible to take a value of 1 ... 5. The third round follows the same rules. At the end, the leftover sum is taken as offset for the value.


An example with 1, ..., 5 values and 5 elements with a sum of 15 and all possibilities:

min:     1
max:     5
length:  5
sum:    15

smin = (length - index - 1) * min
smax = (length - index - 1) * max
offset = Math.max(sum - smax, min)
random = 1 + Math.min(sum - offset, max - offset, sum - smin - min)

    index     sum    sum min  sum max   random   offset
  -------  -------  -------  -------  -------  -------
_      0       15        4       20        5        1
       1       14        3       15        5        1
       1       13        3       15        5        1
       1       12        3       15        5        1
       1       11        3       15        5        1
_      1       10        3       15        5        1
       2       13        2       10        3        3
       2       12        2       10        4        2
       2       11        2       10        5        1
       2       10        2       10        5        1
       2        9        2       10        5        1
       2        8        2       10        5        1
       2        7        2       10        5        1
       2        6        2       10        4        1
_      2        5        2       10        3        1
       3       10        1        5        1        5
       3        9        1        5        2        4
       3        8        1        5        3        3
       3        7        1        5        4        2
       3        6        1        5        5        1
       3        5        1        5        4        1
       3        4        1        5        3        1
       3        3        1        5        2        1
_      3        2        1        5        1        1
       4        5        0        0        1        5
       4        4        0        0        1        4
       4        3        0        0        1        3
       4        2        0        0        1        2
       4        1        0        0        1        1

The example code takes the target 1, ..., 4 with a length of 4 parts and a sum of 10.

function getRandom(min, max, length, sum) {
    return Array.from(
        { length },
        (_, i) => {
            var smin = (length - i - 1) * min,
                smax = (length - i - 1) * max,
                offset = Math.max(sum - smax, min),
                random = 1 + Math.min(sum - offset, max - offset, sum - smin - min),
                value = Math.floor(Math.random() * random + offset);

            sum -= value;
            return value;
        }
    );
}

console.log(Array.from({ length: 10 }, _ => getRandom(1, 4, 4, 10).join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 52
Nina Scholz Avatar answered Sep 24 '22 06:09

Nina Scholz