代码之家  ›  专栏  ›  技术社区  ›  breking bed

单击按钮时如何随机选择唯一编号

  •  0
  • breking bed  · 技术社区  · 2 年前

    每次单击按钮时,我都会尝试随机选择唯一的数字。为此,我的职能是:

    const chooseNumber = () => {
        var r = Math.floor(Math.random() * 75) + 1;
        console.log(r)
        while(selectedNumbers.indexOf(r) === -1) {
          selectedNumbers.push(r);
        }
        console.log(selectedNumbers);
      };
    

    但问题是,如果随机数已经在我的列表中,我需要再次单击按钮来生成新的数字,直到它找到列表中没有的数字。但我想直接生成不在列表中的数字,所以我不需要每次都单击按钮。谢谢你的帮助。

    3 回复  |  直到 2 年前
        1
  •  2
  •   vanowm    2 年前

    你的方向是正确的,除了 while 循环应用于随机数生成器,而不是将数字推入数组:

    const selectedNumbers = [];
    const chooseNumber = () => {
        let r;
        do
        {
          r = Math.floor(Math.random() * 75) + 1;
        }
        while(selectedNumbers.indexOf(r) > -1)
        selectedNumbers.push(r);
        console.log(r, "["+selectedNumbers+"]");
      };
    <button onclick="chooseNumber()">Generate</button>

    请注意,这最终可能会导致冻结,因为如果阵列已满,则不会进行故障保护检查,所以要进行战斗,我们还应该检查阵列的长度:

    const selectedNumbers = [];
    const maxNumber = 75;
    const chooseNumber = () => {
      let r;
      do
      {
        r = ~~(Math.random() * maxNumber) + 1;
      }
      while(selectedNumbers.indexOf(r) > -1 && selectedNumbers.length < maxNumber)
      if (selectedNumbers.length < maxNumber)
        selectedNumbers.push(r);
      else
        console.log("array is full");
    
      console.log(r, "["+selectedNumbers+"]");
    };
    
    
    for(let i = 0; i < 76; i++)
    {
      chooseNumber();
    }
    <按钮onclick=“chooseNumber()”>生成(<)/按钮(>);
        2
  •  0
  •   Nimarel    2 年前

    不需要while循环。您可以使用“if”语句。

    为了避免再次单击按钮,可以执行如下递归函数:

    const chooseNumber = () => {
        var r = Math.floor(Math.random() * 75) + 1;
        console.log(r)
        if(selectedNumbers.indexOf(r) === -1) {
          selectedNumbers.push(r);
          console.log(selectedNumbers);
        } else {
          chooseNumber();
        }
    };
    
        3
  •  0
  •   jsejcksn    2 年前

    不要依赖循环在有限的范围内生成唯一的(看不见的)整数。

    首先,一旦这个范围内的所有值都用完了,就没有可能了,所以在下一次调用时,您将处于一个无休止的循环中。

    其次,这是对处理器的浪费,因为每次调用都会生成无用的值。

    相反,提前(一次)生成范围内的所有值,然后对它们进行洗牌,并在每次调用时从数组中获取最后一个值(如果没有剩余值,则抛出一个错误):

    /**
     * Durstenfeld shuffle
     *
     * - https://stackoverflow.com/a/12646864/438273
     * - https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
     */
    function shuffleArray (array) {
      for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
      }
    }
    
    /** Get shuffled array of all integers in range */
    function generateShuffledIntegerArray (min, max) {
      const arr = [];
      for (let i = min; i <= max; i += 1) arr.push(i);
      shuffleArray(arr);
      return arr;
    }
    
    const getUniqueInt = (() => {
      const numbers = generateShuffledIntegerArray(1, 75);
    
      return () => {
        const n = numbers.pop();
        if (typeof n === 'number') return n;
        throw new Error('No unique numbers remaining');
      };
    })();
    
    // Will log 75 integers, then throw on the 76th invocation:
    for (let i = 1; i <= 76; i += 1) {
      const n = getUniqueInt();
      console.log(`${i}:`, n);
    }

    Code in TypeScript Playground