javascript 将数字拆分为4个随机数字

xoshrz7s  于 2023-11-15  发布在  Java
关注(0)|答案(9)|浏览(146)

我想把10分成4个随机数的数组,但不能是0或大于4。例如[1,2,3,4][1,4,4,1][4,2,3,1]
我想这是一个简单的问题,但由于某种原因,我想不出如何做到这一点。如果有人有一些指导,这将是非常有帮助的!
编辑:这是我现在的代码,但我也生成了一个总数在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;
    }
  }

字符串

mftmpeh8

mftmpeh81#

你可以创建所有可能的组合,然后选择一个随机数组。

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(' ')));

个字符

一种不需要所有可能组合列表就能获取随机值的算法

它的工作原理是使用一个随机值的因子和一个偏移量,基于实际和,索引,下一个索引所需的最小和,以及最大和。
偏移量通常是最小和,或者是和与最大和之差的较大值。为了获得因子,取三个值作为最小值,用于乘以随机值。
该表根据给定值和获取所有值的迭代,说明了总和的所有可能值和所需的迭代。
在开始时,和是用于小部分分布的值。结果是第二个块的剩余和为14 ... 10,因为可以取1 ... 5的值。第三轮遵循相同的规则。在结束时,剩余的和被用作值的偏移。

一个1,.,5值和5元素的例子,其总和为15和所有可能性:

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


示例代码采用目标1,...,4,长度为4部分,总和为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; }
13z8s7eq

13z8s7eq2#

有点晚了,但我发现这是一个有趣的任务,所以在这里你去思考。我的方法不需要创建所有分区,它也不依赖于纯粹的运气找到一个随机匹配,它是紧凑的,它应该是公正的。
即使在使用大值时,只要max没有太大的限制,它也能有效地工作。

const len = 4;
const total = 10;
const max = 4;

let arr = new Array(len);
let sum = 0;
do {
  // get some random numbers
  for (let i = 0; i < len; i++) {
    arr[i] = Math.random();
  }
  // get the total of the random numbers
  sum = arr.reduce((acc, val) => acc + val, 0);
  // compute the scale to use on the numbers
  const scale = (total - len) / sum;
  // scale the array
  arr = arr.map(val => Math.min(max, Math.round(val * scale) + 1));
  // re-compute the sum
  sum = arr.reduce((acc, val) => acc + val, 0);
  // loop if the sum is not exactly the expected total due to scale rounding effects
} while (sum - total);

console.log(arr);

字符串

dtcbnfnu

dtcbnfnu3#

最简单的解决办法就是暴力破解。
1.创建一个while循环来嵌套计算
1.在循环中,创建一个空数组,并使用随机值填充它,直到达到长度
1.检查数组的和是否是您想要的值,如果是,则中断循环
上面的应该运行,直到你有一个结果。
但有两件事值得考虑。
1.你可以很容易地测试一个解决方案是否可行,通过计算,length-of-array times minimum-value 不大于和,length-of-array times maximum-value 不小于和。
1.基于随机条件的循环可能永远运行,因此最大迭代量可能是可取的。
这两点都在下面的片段中考虑:

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 = "<thead><tr><th>Number to split</th><th>Number of splits</th><th>Max value</th><th>Min value</th><th>Run</th></tr></thead>" +
  "<tbody><tr><th><input id=\"number-to-split\" value=\"10\" type=\"number\" min=\"1\"/></th><th><input id=\"number-of-splits\" value=\"4\" type=\"number\" min=\"1\"/></th><th><input id=\"max-value\" type=\"number\" min=\"1\" value=\"4\"/></th><th><input id=\"min-value\" type=\"number\" min=\"1\" value=\"1\"/></th><th><input id=\"run\" type=\"button\" value=\"Run\"/></th></tr></tbody>";
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';
      }
    });
};

字符串

编辑1 -大计算

使用requestAnimationFramePromises,代码现在可以异步执行,这允许更长的计算时间,而不会打扰用户。
我还使random函数与剩余的范围成比例,大大减少了大数字所需的计算量。

6kkfgxo0

6kkfgxo04#

基本上,您需要10的分区(参见https://en.wikipedia.org/wiki/Partition_(number_theory)),并在结果集上应用您的条件。

// Partition generator taken from 
// https://gist.github.com/k-hamada/8aa85ac9b334fb89ac4f

function* partitions(n) {

    if (n <= 0) throw new Error('positive integer only');
    yield [n];

    var x = new Array(n);
    x[0] = n;
    for (var i = 1; i < n; i++) x[i] = 1;

    var m = 0, h = 0, r, t;
    while (x[0] != 1) {
        if (x[h] == 2) {
            m += 1;
            x[h] = 1;
            h -= 1;
        } else {
            r = x[h] - 1;
            x[h] = r;

            t = m - h + 1;
            while (t >= r) {
                h += 1;
                x[h] = r;
                t -= r;
            }
            m = h + (t !== 0 ? 1 : 0);
            if (t > 1) {
                h += 1;
                x[h] = t;
            }
        }
        yield x.slice(0, m + 1);
    }
}

results = [];
// Get all possible partitions for your number
for (var partition of partitions(10)) {
    // Apply your conditions (must be 4 numbers, none of them greater than 4)
    if(partition.length != 4 || partition.some((x) => x > 4)) continue;
    results.push(partition);
}
console.log(results);

字符串

8dtrkrch

8dtrkrch5#

鉴于:
在一个n个正数的集合中,它们的总和为S,其中至少有一个将小于S除以n(S/n)
并且你想要一个结果集正好是4个数字
你可以使用以下算法:
1.从范围[1,floor(S/n)]中获取一个随机数,在这种情况下floor(10/4)= 2,因此在范围[1,2]中获取一个随机数。让我们将其标记为x1。
1.从范围[1,floor((S - x1)/(n - 1))]中获取一个随机数。让我们将其标记为x2。
1.从范围[1,floor((S-x1- x2)/(n - 2))]中获取一个随机数。
1.继续,直到得到x(n-1)。
1.通过执行S-x1- x2.... - x(n-1)得到最后一个数字。
最后,对上述算法进行扩展,增加一个限制随机数上限的条件
n步骤,你可以得到一个集合。

function getRandomInt(min, max) {
       return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    function getRandomCollection(min, max, length, sum) {
        var collection = [];
        var leftSum = sum - (min - 1);

        for(var i = 0; i < length - 1; i++) {
             var number = getRandomInt(min, Math.min(Math.ceil(leftSum/(length - i)), max));
             leftSum -= number;
             collection.push(number);
        }
        leftSum += min - 1;
        while(leftSum > max) {
             var randomIndex = Math.floor(Math.random() * collection.length);
             if(collection[randomIndex] < max) {
                  collection[randomIndex]++;
                  leftSum--;
             }
        }
        
        collection.push(leftSum);
        return collection;
    }
    console.log(getRandomCollection(1, 4, 4, 10).join(' + ') + ' = 10');
    console.log(getRandomCollection(3, 20, 10, 100).join(' + ') + ' = 100');

字符串
参考
My answer using the same algorithm for another question

zazmityj

zazmityj6#

快速、简单,但有偏见和非确定性终止

function partition(sum, len, min, max) {
    const a = Array(len).fill(min)
    while (a.reduce((acc,val)=>acc+val) < sum) {
        const i = Math.random()*len|0
        if (a[i] < max) a[i]++
    }
    return a
}

console.log(Array(10).fill().map(_=>partition(10, 4, 1, 4).join(' ')))

个字符
while循环可以无限小的概率永远循环。为了防止这种情况,你可以保留另一个“有效索引”数组,并在值达到max时删除其中的键。

3lxsmp7m

3lxsmp7m7#

我只是一个偶然发现这一页的中学数学老师,但我想知道这是否是一个好的解决方案:

nums = [1,1,1,1];
full=[0,0,0,0];
for(i=0;i<6;i++){
    do {
        now=Math.floor(Math.random() * 4);
    } while (full[now]==1);
    nums[now]=nums[now]+1;
    if (nums[now]==4){
        full[now]=1;
    }
}

字符串

hzbexzde

hzbexzde8#

这将计算从1到4的随机数
根据需要将其 Package 在函数中以生成数组

Math.floor(Math.random() * 4) + 1

字符串

var randomNumber = Math.floor(Math.random() * 4) + 1 ;
console.log(randomNumber);

kognpnkq

kognpnkq9#

太简单了。

var values = null;
while(true) {
    var currentSum = 0;
    var expectedSum = 10;
    values = [];
    while(expectedSum !== currentSum) {
        //var value = Math.floor(Math.random() * 9) + 1;
        var value = Math.floor(Math.random() * 4) + 1;
        if(value + currentSum > expectedSum) {
            continue;
        }
        currentSum += value;
        values.push(value);
    }
    if(values.length === 4) {
        break;
    } else {
        console.log('false iteration')
    }
}
console.log(values);

字符串

相关问题