我有一个这样的数组:

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

我如何随机化/打乱它?


当前回答

为了更灵活,可以添加另一个参数。在这种情况下,可以从数组中获取一个随机数组,并指定新数组的长度:

  function shuffle(array, len = array.length) {
        for (let i = array.length - 1; i > 0; i--) {
            let j = Math.floor(Math.random() * (i + 1));
            [array[i], array[j]] = [array[j], array[i]];
        }

        return array.slice(0, len);
    }

其他回答

对CoolAJ86答案的简单修改,不修改原始数组:

 /**
 * Returns a new array whose contents are a shuffled copy of the original array.
 * @param {Array} The items to shuffle.
 * https://stackoverflow.com/a/2450976/1673761
 * https://stackoverflow.com/a/44071316/1673761
 */
const shuffle = (array) => {
  let currentIndex = array.length;
  let temporaryValue;
  let randomIndex;
  const newArray = array.slice();
  // While there remains elements to shuffle...
  while (currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;
    // Swap it with the current element.
    temporaryValue = newArray[currentIndex];
    newArray[currentIndex] = newArray[randomIndex];
    newArray[randomIndex] = temporaryValue;
  }
  return newArray;
};

我想分享解决这个问题的百万种方法之一=)

function shuffleArray(array = ["banana", "ovo", "salsicha", "goiaba", "chocolate"]) {
const newArray = [];
let number = Math.floor(Math.random() * array.length);
let count = 1;
newArray.push(array[number]);

while (count < array.length) {
    const newNumber = Math.floor(Math.random() * array.length);
    if (!newArray.includes(array[newNumber])) {
        count++;
        number = newNumber;
        newArray.push(array[number]);
    }
}

return newArray;

}

这是一个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开始),从而跳过最终元素。

算法运行时间为O(n)。请注意,洗牌是在适当的位置完成的,因此如果您不想修改原始数组,请首先使用.sslice(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]];
    }
}

添加到@Laurens Holsts的答案。这是50%的压缩。

function shuffleArray(d) {
  for (var c = d.length - 1; c > 0; c--) {
    var b = Math.floor(Math.random() * (c + 1));
    var a = d[c];
    d[c] = d[b];
    d[b] = a;
  }
  return d
};

警告不建议使用这种算法,因为它效率低且具有强烈的偏见;参见注释。它被留在这里供将来参考,因为这种想法并不罕见。

[1,2,3,4,5,6].sort( () => .5 - Math.random() );

这https://javascript.info/array-methods#shuffle-阵列教程直接解释了这些差异。