无法弄清楚为什么我的math.random在for循环中返回错误的值

时间:2019-03-04 18:09:06

标签: javascript

我有一个由25个插槽组成的数组,我需要将前5个数字设置为1-15,接下来的5个数字设置为16-30,依此类推。

我已经完成了一个for循环和一个switch案例来实现此目的,但是它返回了错误的值。在forloop之外,它返回正确的数字。

var num = [];
var col = [0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4];
var card = [];

    // Filling the num array
function fill(number) {
    for(let i = 1; i < number+1; i++) {
        num.push([i]);
    } // Fills the array from 1 to 'number' and will have no duplicates
}

fill(76);

function fillCard() {
for(let i = 0; i < col.length; i++) {
    switch (col[i]) {
        case 0:
            getRandom(0,15);
            break;
        case 1:
            getRandom(16,30);
            break;
        case 2:
            getRandom(31,45);
            break;
        case 3:
            getRandom(46,60);
            break;
        case 4:
            getRandom(61,75);
            break;
        default:
            console.log('error');
        }
    }
}

function getRandom(min,max) {
    var x = Math.floor(Math.random() * (max - min + 1) ) + min;
    card.push(num[x]);
    num.splice(x,1);
}

3 个答案:

答案 0 :(得分:2)

更新

后续评论清楚地表明,这是试图在每个部分中包含不重复的随机数。

这可能是我的方法:

function randoms(max, count) {
  // todo: error if count > max
  const arr = new Array(max + 1)
  for (let i = max; i > max - count; i--) {
    const j = Math.floor(Math.random() * (i + 1))
    const temp = arr[j] || j
    arr[j] = arr[i] || i
    arr[i] = temp
  }
  return arr.slice(-count)
}

const ranges = [ [1, 15], [16, 30], [31, 45], [46, 60], [61, 75] ]

const makeCard = (ranges, count) => ranges.map(
  ([min, max]) => randoms(max - min + 1, count).map(n => n + min)
).reduce((a, b) => a.concat(b), [])

console.log(makeCard(ranges, 5))

randomsFisher-Yates随机播放的一种版本,在对固定数量的值进行随机播放后会停止。 (我是从我的earlier answer那里拿来的。)。每个对此的调用都会在0 - (max - min)范围内选择五个不同的数字,然后在内部min调用中向其中添加map

map中的外部makeCard调用为每个范围调用随机函数,这将产生如下结果:

[
  [15, 10, 14, 12, 5],
  [17, 30, 29, 20, 16],
  [35, 34, 31, 46, 37],
  [53, 58, 46, 54, 60],
  [70, 65, 75, 74, 62]
]

然后,我们在结果上调用reduce并传递一个函数,该函数将其两个参数简单地连接起来,从而将其转换为一个列表。在某些时候,我们将可以改用Array.prototype.flat

此方法的一个优点是您可以轻松更改范围列表,因此它们不必都具有相等的长度。而且,如果您希望对范围使用不同的计数,则也可以在范围内移动count变量(例如,[ [5, 16, 30], [7, 31, 50] ]用于“在16和60之间选择5个不同的数字,在31和50之间选择7个不同的数字。”这将仅涉及对代码的小改动。


(旧答案)

简单更改

对代码进行的最小更改即可完成您想要的操作,只是将您选择的值直接推到数组上即可。 (我不知道num应该在这里。)此版本可以做到这一点:

var col = [0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4];
var card = [];

function fillCard() {
for(let i = 0; i < col.length; i++) {
    switch (col[i]) {
        case 0:
            getRandom(0,15);
            break;
        case 1:
            getRandom(16,30);
            break;
        case 2:
            getRandom(31,45);
            break;
        case 3:
            getRandom(46,60);
            break;
        case 4:
            getRandom(61,75);
            break;
        default:
            console.log('error');
        }
    }
}

function getRandom(min,max) {
    var x = Math.floor(Math.random() * (max - min + 1) ) + min;
    card.push(x)
}

fillCard()

console.log(card)

更多高级

但是,如果您对更高级的技术感兴趣,可以简单地写:

const card = [...new Array(25)].map(
  (_, i) => Math.floor(Math.random() * 15) + (15 * Math.floor(i / 5)) + 1
)

console.log(card)

说明

第二个版本以[...new Array(25)]开始。 new Array(25)部分将创建一个数组,该数组不包含任何实际元素,但人工长度为25。用花括号([ ])和散布运算符(...)包裹起来,将其变成数组具有25个实际值,所有这些值恰好是undefined

[undefined, undefined, undefined, ... undefined]

现在,我们可以在该数组上map,这是对每个值应用函数以创建全新数组的过程。我们传递给地图的功能是

(_, i) => Math.floor(Math.random() * 15) + (15 * Math.floor(i / 5)) + 1,

它有两个参数,但是由于我们将忽略第一个参数,因此我们将其命名为_。这个名字没有魔力,但是向读者发出一个普遍信号,即该参数并不重要。不过,我们使用第二个参数。 i是我们正在查看的数组中的索引。

其余的是相当简单的数学。 5代表每个组中的元素数。 15代表随机范围的大小。如果需要,我们可以编写一个接受这两个值作为参数并返回数组的函数。

答案 1 :(得分:0)

因此,有些事情出了问题-您正在根据更改的值进行循环,但是每次将i设置为可能会超出循环长度的值。< / p>

仔细研究一下逻辑,然后告诉我这是否正确:

Task: create an array of 25 numbers, each lot of five to be in a different range. The first five between 0 and 15, the next five between 16 and 30, the next five between 31 and 45, the next 46 to 60, and final five between 61 and 75.

* Create an array to define the 'steps'. Based on those steps, we switch our min and max for these array values.

* Create an array to store each of the random numbers.

* While we have a valid length of 'steps' array, use the first to define the current range.

* Use a switch statement to determine the min/max of the current random member.

* remove the first member of the 'steps' array.

如果这些步骤与您正在考虑的步骤相似,则可能是您想得太多了。相反,只需执行以下操作即可:使用while循环,检查col.length仍大于零,然后基于col[0]进行切换。

这是它的外观:

var col = [0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4];
var card = [];

function fillCard() {
while(col.length > 0) {
    switch (col[0]) {
        case 0:
            getRandom(0,15);
            break;
        case 1:
            getRandom(16,30);
            break;
        case 2:
            getRandom(31,45);
            break;
        case 3:
            getRandom(46,60);
            break;
        case 4:
            getRandom(61,75);
            break;
        default:
            console.log('error');
        }
    }
}

function getRandom(min,max) {
    var x = Math.floor(Math.random() * (max-min) ) +min;
    card.push(x);
    col.shift();
}

fillCard();
console.log(card)

编辑:上面的方法很好,对于我们给的原始规格。但是,如果您需要在该范围内生成UNIQUE随机数,则需要执行其他过程:

  1. 创建该范围内所有可能值的数组。
  2. 在该范围内随机选择一个可能的值。
  3. 删除所选值,从而使其具有唯一性。

这是可能的编码方式:

let col = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4],
  possibles = [],
  card = [];

function fillCard() {
  /**
   * First, create an array of possible values. This will be a nested
   *   array, each sub-array containing fifteen unique sequential
   *   values within our given range.
   */
  for (let i = 0; i <= 4; i++) {
    let possibleSubArray = [];
    for (let j = 0; j <= 15; j++) {
      possibleSubArray.push(i * 15 + j);
    }
    possibles.push(possibleSubArray);
  }
  
  // Let's see that list of possibles.
  //  console.log(possibles);
  
  // Now, we use col to identify which of the sub-arrays we want to
  //  get our unique value from.
  for (let i = 0; i < col.length; i++) {
    // getRandom no longer takes a min/max. Now it takes the index
    //  to the given sub-array.
    getRandom(col[i]);
  }

  // This creates a random number based on the length of the subarray
  //  length, then pushes the value at that index onto our 'card'
  //  array. At that point, it removes that number from our 'possibles'
  //  array, thus rendering it unique.
  function getRandom(possiblesSubArrayIndex) {
    let min = 0, max = possibles[possiblesSubArrayIndex].length;
    var x = Math.floor(Math.random() * (max - min)) + min;
    // push that random number onto our 'card'
    card.push(possibles[possiblesSubArrayIndex][x]);
    // and remove it from the possible numbers.
    possibles[possiblesSubArrayIndex].splice(x, 1);
  }
}

  fillCard();
  console.log(card);
  // If you want to see what we DIDN'T use for uniques...
//  console.log(possibles);

答案 2 :(得分:0)

我认为,这对您有用。

Math.floor(Math.random()* max + 1 , min)