如何随机化(随机排列)一个JavaScript数组?

2022-08-29 21:57:10

我有一个这样的数组:

var arr1 = ["a", "b", "c", "d"];

如何随机化/随机播放?


答案 1

事实上的无偏洗牌算法是Fisher-Yates(又名Knuth)Shuffle

您可以在此处看到出色的可视化效果(以及与此链接的原始帖子))

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

有关所用算法的更多信息


答案 2

以下是 Durstenfeld shuffle 的 JavaScript 实现,这是 Fisher-Yates 的优化版本:

/* Randomize array in-place using Durstenfeld shuffle algorithm */
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 开始),从而跳过最后一个元素。

算法运行时为 。请注意,随机播放是就地完成的,因此,如果您不想修改原始数组,请先使用 .slice(0) 复制它。O(n)


编辑:更新到 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]];
    }
}