首页  >  问答  >  正文

重写后的标题为:学习如何对 JavaScript 数组进行随机排序(洗牌)

<p>我有一个像这样的数组:</p> <pre class="brush:php;toolbar:false;">var arr1 = ["a", "b", "c", "d"];</pre> <p>如何对它进行随机化/洗牌?</p>
P粉818125805P粉818125805395 天前519

全部回复(2)我来回复

  • P粉810050669

    P粉8100506692023-08-22 00:30:17

    这是一个JavaScript实现的Durstenfeld shuffle,它是Fisher-Yates算法的优化版本:

    /* 使用Durstenfeld shuffle算法原地随机化数组 */
    function shuffleArray(array) {
        for (var i = array.length - 1; i > 0; i--) {
            var j = Math.floor(Math.random() * (i + 1));
            var temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
    }

    它为每个原始数组元素选择一个随机元素,并从下一次抽取中排除它,就像从一副牌中随机抽取一样。

    这个巧妙的排除操作将被选中的元素与当前元素交换,然后从剩余的元素中选择下一个随机元素,为了最佳效率而向后循环,确保随机选择被简化(它总是可以从0开始),从而跳过最后一个元素。

    算法的运行时间为O(n)。请注意,洗牌是原地进行的,所以如果你不想修改原始数组,请先使用.slice(0)创建一个副本。


    编辑:更新到ES6 / ECMAScript 2015

    新的ES6允许我们同时赋值两个变量。当我们想要交换两个变量的值时,这特别方便,因为我们可以在一行代码中完成。这是使用此功能的同一函数的更短形式。

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

    回复
    0
  • P粉553428780

    P粉5534287802023-08-22 00:07:03

    事实上,无偏的洗牌算法是Fisher-Yates(又称为Knuth)洗牌算法

    你可以在这里看到一个很棒的可视化效果(原始帖子链接到这里

    function shuffle(array) {
      let currentIndex = array.length,  randomIndex;
    
      // While there remain elements to shuffle.
      while (currentIndex != 0) {
    
        // Pick a remaining element.
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;
    
        // And swap it with the current element.
        [array[currentIndex], array[randomIndex]] = [
          array[randomIndex], array[currentIndex]];
      }
    
      return array;
    }
    
    // Used like so
    var arr = [2, 11, 37, 42];
    shuffle(arr);
    console.log(arr);

    回复
    0
  • 取消回复