我有一个这样的数组:

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

我如何随机化/打乱它?


当前回答

我认为还没有人给出一个可以在不扩展Array原型的情况下连接起来的解决方案(这是一个糟糕的做法)。使用稍微鲜为人知的reduce(),我们可以轻松地以允许串联的方式进行混洗:

var randomsquares = [1, 2, 3, 4, 5, 6, 7].reduce(shuffle).map(n => n*n);

您可能希望传递第二个参数[],否则如果尝试在空数组上执行此操作,则会失败:

// Both work. The second one wouldn't have worked as the one above
var randomsquares = [1, 2, 3, 4, 5, 6, 7].reduce(shuffle, []).map(n => n*n);
var randomsquares = [].reduce(shuffle, []).map(n => n*n);

让我们将shuffle定义为:

var shuffle = (rand, one, i, orig) => {
  if (i !== 1) return rand;  // Randomize it only once (arr.length > 1)

  // You could use here other random algorithm if you wanted
  for (let i = orig.length; i; i--) {
    let j = Math.floor(Math.random() * i);
    [orig[i - 1], orig[j]] = [orig[j], orig[i - 1]];
  }

  return orig;
}

您可以在JSFiddle或此处看到它的实际应用:

var shuffle=(all,one,i,orig)=>{如果(i!==1)返回全部;//你可以在这里使用其他随机算法for(设i=原始长度;i;i-){设j=数学地板(Math.random()*i);[原始[i-1],原始[j]]=[原始[j],原始[i-1]];}返回原点;}对于(变量i=0;i<5;i++){var randomarray=[1,2,3,4,5,6,7]。reduce(shuffle,[]);console.log(JSON.stringify(randomarray));}

其他回答

我使用以下两种方法:

此方法不会修改原始数组

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

$=(m)=>控制台日志(m);//----将此方法添加到Array类Array.prototype.shuffle=函数(){return this.sort(()=>.5-Math.random());};$([1,65,87,45101,33,9].shuffle());$([1,65,87,45101,33,9].shuffle());$([1,65,87,45101,33,9].shuffle());$([1,65,87,45101,33,9].shuffle());$([1,65,87,45101,33,9].shuffle());

我在考虑在控制台上粘贴oneliner。sort的所有技巧都给出了错误的结果,下面是我的实现:

 ['Bob', 'Amy', 'Joy'].map((person) => `${Math.random().toFixed(10)}${person}`).sort().map((person) => person.substr(12));

但不要在生产代码中使用它,它不是最佳的,只适用于字符串。

NEW!

更短,可能更快的Fisher Yates洗牌算法

它使用while---按位到底数(最多10个十进制数字(32位))移除了不必要的封盖和其他东西


function fy(a,b,c,d){//array,placeholder,placeholder,placeholder
 c=a.length;while(c)b=Math.random()*(--c+1)|0,d=a[c],a[c]=a[b],a[b]=d
}

脚本大小(以fy作为函数名):90字节

演示http://jsfiddle.net/vvpoma8w/

*可能在除chrome之外的所有浏览器上都更快。

如果您有任何问题,请提问。

EDIT

是的,它更快

性能:http://jsperf.com/fyshuffle

使用排名靠前的函数。

编辑计算过多(不需要--c+1),没有人注意到

更短(4字节)和更快(测试!)。

function fy(a,b,c,d){//array,placeholder,placeholder,placeholder
 c=a.length;while(c)b=Math.random()*c--|0,d=a[c],a[c]=a[b],a[b]=d
}

在其他地方缓存var rnd=Math.random,然后使用rnd()也会稍微提高大数组的性能。

http://jsfiddle.net/vvpoma8w/2/

可读版本(使用原始版本。这会更慢,vars是无用的,像closures&“;”,代码本身也更短……也许读一下如何“缩小”Javascript代码,顺便说一句,你不能像上面那样用Javascript缩小器压缩以下代码。)

function fisherYates( array ){
 var count = array.length,
     randomnumber,
     temp;
 while( count ){
  randomnumber = Math.random() * count-- | 0;
  temp = array[count];
  array[count] = array[randomnumber];
  array[randomnumber] = temp
 }
}

最短的arrayShuffle函数

function arrayShuffle(o) {
    for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
    return o;
}