我有一个这样的数组:

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

我如何随机化/打乱它?


当前回答

Array.prototype.shuffle=function(){
   var len = this.length,temp,i
   while(len){
    i=Math.random()*len-- |0;
    temp=this[len],this[len]=this[i],this[i]=temp;
   }
   return this;
}

其他回答

 const arr = [
  { index: 0, value: "0" },
  { index: 1, value: "1" },
  { index: 2, value: "2" },
  { index: 3, value: "3" },
];
let shuffle = (arr) => {
  let set = new Set();
  while (set.size != arr.length) {
    let rand = Math.floor(Math.random() * arr.length);
    set.add(arr[rand]);
  }
  console.log(set);
};
shuffle(arr);

考虑将其应用于本地或新的不可变数组,遵循其他解决方案,以下是建议的实现:

Array.prototype.shuffle = function(local){
  var a = this;
  var newArray = typeof local === "boolean" && local ? this : [];
  for (var i = 0, newIdx, curr, next; i < a.length; i++){
    newIdx = Math.floor(Math.random()*i);
    curr = a[i];
    next = a[newIdx];
    newArray[i] = next;
    newArray[newIdx] = curr;
  }
  return newArray;
};

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
 }
}

我认为还没有人给出一个可以在不扩展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));}

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

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