如何在JavaScript中将数字n分成x部分,其中所有部分的总和等于数字?

kyks70gy  于 12个月前  发布在  Java
关注(0)|答案(7)|浏览(80)

我有一个数字,我需要分成五部分。但是,我希望每个部分都是一个随机数。但是当所有的部分加在一起时,它们等于原来的数字。我不知道如何使用JavaScript来实现这一点。此外,我不希望分割部分的最小值为0或1,我想自己设置最小值。
例如,数字是450。我希望分割的部分不少于60。首先,数组是[60,60,60,60,60]。但是我想随机化一下,这样它们加起来就是450。做这件事的最好方法是什么?
谢谢你,谢谢!
这是我迄今为止所尝试的:

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;
}
mkshixfv

mkshixfv1#

设你的数是N,pn是第n部分。要获得5个部件:

  • p1 = 0和N之间的随机数
  • p2 = 0和N-pl之间的随机数
  • p3 = 0和N-p2- p1之间的随机数
  • p4 = 0和N-p3- p2 - p1之间的随机数
  • p5 = N-p4- p3 - p2 - p1

编辑2017

  • 为了让它看起来更随机,生成数字后将其打乱 *

编辑2020

我想一些代码不会伤害。使用ES 7生成器:

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

gg58donl

gg58donl2#

将五个最小值(例如min = 60)相加:

var minSum = 5 * min

然后求出原始数(orNumber = 450)和minSum之间的差。

var delta = orNumber - minSum

现在你得到4个不同的随机数,范围从0到1。
按升序排列这些数字。
这些随机受试者中的每一个都执行以下操作:

  • 从最后一个中减去它(或零表示第一个)
  • 将这个数字乘以delta,得到其中一个部分。

最后一部分是delta减去所有其他部分。
然后,您只需将min添加到所有部件。

5vf7fwbs

5vf7fwbs3#

该函数生成从0到1的随机数,将它们相加以计算出它们需要乘以什么才能提供正确的范围。它的好处是所有的数字都被公平地分配。

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}));
ecbunoof

ecbunoof4#

可以使用do..while循环从原始数字中减去最小数字,保留原始数字的副本,以便在循环结束时将余数推送到数组中

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

要随机化结果数组的输出,请选择一个大于min且小于n的数字,以创建特定范围内的随机数

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);
cs7cruho

cs7cruho5#

我为初学者做了一个更长的版本。

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);
}
kxe2p93d

kxe2p93d6#

有更有效的方法来编码,但为了解释解决问题的逻辑,这一步一步地走,转换值并解释逻辑。

// 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

svmlkihl

svmlkihl7#

评分最高的答案不包括最小变量,所以我做了一些调整:

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

相关问题