我有一个这样的数组:

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

我如何随机化/打乱它?


当前回答

为了完整起见,除了Fischer Yates的Durstenfeld变体外,我还要指出Sattolo的算法,它只需要一个微小的变化,就会导致每个元素都发生变化。

function sattoloCycle(arr) {
   for (let i = arr.length - 1; 0 < i; i--) {
      const j = Math.floor(Math.random() * i);
      [arr[i], arr[j]] = [arr[j], arr[i]];
   }
   return arr
}

不同之处在于如何计算随机索引j,Math.random()*i与Math.random*(i+1)。

其他回答

编辑:此答案不正确

参见评论和https://stackoverflow.com/a/18650169/28234.这里留作参考,因为这种想法并不罕见。


对于小型阵列,一个非常简单的方法就是:

const someArray = [1, 2, 3, 4, 5];

someArray.sort(() => Math.random() - 0.5);

它可能效率不高,但对于小型阵列来说,这很好。这里有一个例子,你可以看到它有多随机(或不随机),以及它是否适合你的用例。

const resultsEl=document.querySelector(“#results”);const buttonEl=document.querySelector(“#trigger”);常量生成器数组和随机化=()=>{常量someArray=[0,1,2,3,4,5,6,7,8,9];someArray.sort(()=>Math.random()-0.5);return someArray;};const renderResultsToDom=(结果,el)=>{el.innerHTML=results.join(“”);};buttonEl.addEventListener('click',()=>renderResultsToDom(generateArray AndRandomize(),resultsEl));<h1>随机化</h1><button id=“trigger”>生成</button><p id=“results”>0 1 2 3 4 5 6 7 8 9</p>

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

递归解决方案:

function shuffle(a,b){
    return a.length==0?b:function(c){
        return shuffle(a,(b||[]).concat(c));
    }(a.splice(Math.floor(Math.random()*a.length),1));
};

使用ES6功能的现代短内联解决方案:

['a','b','c','d'].map(x => [Math.random(), x]).sort(([a], [b]) => a - b).map(([_, x]) => x);

(出于教育目的)

所有其他答案都基于Math.random(),它很快,但不适用于密码级别的随机化。

下面的代码使用了众所周知的Fisher Yates算法,同时利用Web Cryptography API实现了随机化的加密级别。

变量d=[1,2,3,4,5,6,7,8,9,10];函数洗牌(a){var x,t,r=新Uint32Array(1);对于(var i=0,c=a.length-1,m=a.length;i<c;i++,m-){crypto.getRandomValues(r);x=数学楼层(r/65536/65536*m)+i;t=a[i],a[i]=a[x],a[x]=t;}返回a;}console.log(shuffle(d));