我有一个这样的数组:

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

我如何随机化/打乱它?


当前回答

2019年,我们仍在调整阵列,所以我的方法是:

常量src=[…'abcdefg'];常量shuffle=arr=>[…arr].还原右((res,_,__,s)=>(res.push(s.splice(0|Math.random()*s.length,1)[0]),res),[]);console.log(shuffle(src));.作为控制台包装{最小高度:100%}

其他回答

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

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

(出于教育目的)

不改变源数组的shuffle函数

更新:这里我建议使用一种相对简单(不是从复杂性角度)和较短的算法,它可以很好地处理小型阵列,但在处理大型阵列时,它的成本肯定要比经典的Durstenfeld算法高得多。你可以在对这个问题的回答中找到杜斯滕菲尔德。

原答覆:

如果您不希望shuffle函数改变源数组,可以将其复制到本地变量,然后使用简单的shuffle逻辑完成其余操作。

function shuffle(array) {
  var result = [], source = array.concat([]);

  while (source.length) {
    let index = Math.floor(Math.random() * source.length);
    result.push(source[index]);
    source.splice(index, 1);
  }

  return result;
}

疏解逻辑:选取一个随机索引,然后将相应的元素添加到结果数组中,然后从源数组副本中删除它。重复此操作,直到源阵列变为空。

如果你真的想要简短的话,下面是我能做到的程度:

function shuffle(array) {
  var result = [], source = array.concat([]);

  while (source.length) {
    let index = Math.floor(Math.random() * source.length);
    result.push(source.splice(index, 1)[0]);
  }

  return result;
}

编辑:此答案不正确

参见评论和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>

我使用以下两种方法:

此方法不会修改原始数组

shuffle(array);

功能洗牌(arr){var len=arr.length;var d=长度;var数组=[];变量k,i;对于(i=0;i<d;i++){k=数学楼层(Math.random()*len);array.push(arr[k]);arr.splice(k,1);len=排列长度;}对于(i=0;i<d;i++){arr[i]=阵列[i];}返回arr;}var arr=[“a”,“b”,“c”,“d”];arr=洗牌(arr);控制台日志(arr);

此方法修改原始数组

array.shuffle();

Array.prototype.shuffle=函数(){var len=此长度;var d=长度;var数组=[];变量k,i;对于(i=0;i<d;i++){k=数学楼层(Math.random()*len);array.push(this[k]);此接头(k,1);len=此长度;}对于(i=0;i<d;i++){this[i]=数组[i];}}var arr=[“a”,“b”,“c”,“d”];arr.shuffle();控制台日志(arr);

所有其他答案都基于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));