我有一个这样的数组:

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

我如何随机化/打乱它?


当前回答

罗纳德·费舍尔和弗兰克·耶茨洗牌

ES2015(ES6)版本

Array.prototype.shuffle2 = function () {
    this.forEach(
        function (v, i, a) {
            let j = Math.floor(Math.random() * (i + 1));
            [a[i], a[j]] = [a[j], a[i]];
        }
    );
    return this;
}

Jet优化ES2015(ES6)版本

Array.prototype.shuffle3 = function () {
    var m = this.length;
    while (m) {
        let i = Math.floor(Math.random() * m--);
        [this[m], this[i]] = [this[i], this[m]];
    }
    return this;
}

其他回答

我发现这个变体挂在“作者删除”的答案中,重复了这个问题。与其他一些已经获得许多支持的答案不同,这是:

实际上是随机的不到位(因此名称被打乱而不是打乱)此处尚未出现多个变体

这是一个jsfiddle,显示了它的使用情况。

Array.prototype.shuffled = function() {
  return this.map(function(n){ return [Math.random(), n] })
             .sort().map(function(n){ return n[1] });
}

警告不建议将此答案用于随机化大型阵列、密码学或任何其他需要真正随机性的应用程序,因为其存在偏差且效率低下。元素的位置只是半随机的,它们将倾向于保持更接近其原始位置。看见https://stackoverflow.com/a/18650169/28234.


可以使用Math.random任意决定是否返回1:-1:

[1, 2, 3, 4].sort(() => (Math.random() > 0.5) ? 1 : -1)

尝试运行以下示例:

常量数组=[1,2,3,4];//基于Math.Random返回的值,//任意决定是否返回1:-1const shuffeled=array.sort(()=>{const randomTrueOrFalse=数学random()>0.5;return randomTrueOrFalse?1 : -1});console.log(shuffeled);

只是为了在馅饼里插一根手指。在这里,我介绍了Fisher Yates shuffle的递归实现(我认为)。它给出了统一的随机性。

注意:~~(双颚化符运算符)实际上与正实数的Math.floor()类似。这只是一条捷径。

var shuffle=a=>a.length?a.splice(~~(Math.random()*a.length),1).contat(shuffle(a)):a;console.log(JSON.stringify(shuffle([0,1,2,3,4,5,6,7,8,9]));

编辑:由于使用了.splice(),上面的代码是O(n^2),但我们可以通过交换技巧消除O(n)中的拼接和混洗。

var shuffle=(a,l=a.length,r=~~(Math.random()*l))=>l?([a[r],a[l-1]]=[a[l-1],a[r]],shuffle(a,l-1)):a;var arr=Array.from({length:3000},(_,i)=>i);console.time(“shuffle”);洗牌(arr);console.timeEnd(“shuffle”);

问题是,JS无法与大型递归合作。在这种特殊的情况下,数组大小会受到限制,大约为3000~7000,这取决于浏览器引擎和一些未知的事实。

随机化数组,无重复项

    function randomize(array){
        let nums = [];
        for(let i = 0; i < array.length; ++i){
            nums.push(i);
        }   
        nums.sort(() => Math.random() - Math.random()).slice(0, array.length)
        for(let i = 0; i < array.length; ++i){
            array[i] = array[nums[i]];
        }
    }
    randomize(array);

添加到@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
};