我有一个这样的数组:

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

我如何随机化/打乱它?


当前回答

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

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

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

其他回答

社区表示arr.sort((a,b)=>0.5-Math.random())不是100%随机的!对我测试并建议不要使用此方法!

let arr = [1, 2, 3, 4, 5, 6]
arr.sort((a, b) => 0.5 - Math.random());

但我不确定。所以我写了一些代码来测试!。。。你也可以试试!如果你足够感兴趣!

让data_base=[];对于(设i=1;i<=100;i++){//将100次新的rendom arr推送到data_base!数据基础推送([1,2,3,4,5,6]排序((a,b)=>{return Math.random()-0.5;//使用了社区禁止的方法!:-)}));}//console.log(data_base);//如果你想看数据!让分析={};for(设i=1;i<=6;i++){analysis[i]=阵列(6).填充(0);}for(假设num=0;num<6;num++){for(设i=1;i<=100;i++){let plus=数据基[i-1][num];分析[`${num+1}`][plus-1]++;}}console.log(分析);//分析结果

在100个不同的随机阵列中。(我的分析结果)

{ player> 1   2   3  4   5   6
   '1': [ 36, 12, 17, 16, 9, 10 ],
   '2': [ 15, 36, 12, 18, 7, 12 ],
   '3': [ 11, 8, 22, 19, 17, 23 ],
   '4': [ 9, 14, 19, 18, 22, 18 ],
   '5': [ 12, 19, 15, 18, 23, 13 ],
   '6': [ 17, 11, 15, 11, 22, 24 ]
}  
// player 1 got > 1(36 times),2(15 times),...,6(17 times)
// ... 
// ...
// player 6 got > 1(10 times),2(12 times),...,6(24 times)

正如你所看到的,这不是那么随机!苏。。。不要使用此方法!如果你测试多次,你会看到玩家1获得了很多次(1号)!而球员6在大多数时候都获得了(第6名)!

事实上的无偏洗牌算法是Fisher Yates(又名Knuth)shuffle。

你可以在这里看到一个很棒的可视化效果(以及链接到此的原始帖子)

函数洗牌(数组){let currentIndex=array.length,randomIndex;//而还有一些元素需要洗牌。while(currentIndex!=0){//拾取剩余的元素。randomIndex=数学地板(Math.random()*当前索引);当前索引--;//并将其与当前元素交换。[array[currentIndex],array[randomIndex]]=[array[randomIndex],array[currentIndex]];}返回数组;}//如此使用var arr=[2,11,37,42];洗牌(arr);控制台日志(arr);

有关所用算法的更多信息。

最短的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;
}

首先,在这里查看javascript中不同排序方法的视觉比较。

其次,如果您快速查看上面的链接,您会发现与其他方法相比,随机顺序排序的性能似乎相对较好,同时实现起来非常简单和快速,如下所示:

function shuffle(array) {
  var random = array.map(Math.random);
  array.sort(function(a, b) {
    return random[array.indexOf(a)] - random[array.indexOf(b)];
  });
}

编辑:正如@gregers所指出的,比较函数是用值而不是索引来调用的,这就是为什么需要使用indexOf的原因。注意,由于indexOf在O(n)时间内运行,此更改使代码不太适合较大的数组。

您可以轻松地使用地图和排序:

让unshuffled=['hello','a','t','q',1,2,3,{cats:true}]让洗牌.map(value=>({value,sort:Math.random()})).sort((a,b)=>a.sort-b.sort).map(({value})=>值)console.log(混洗)

我们将数组中的每个元素放在一个对象中,并给它一个随机排序键我们使用随机键排序我们取消映射以获取原始对象

您可以对多态数组进行排序,排序就像Math.random一样随机,这对于大多数目的来说都足够好。

由于元素是根据每次迭代都不会重新生成的一致键进行排序的,并且每次比较都来自相同的分布,因此Math.random分布中的任何非随机性都会被取消。

速度

时间复杂度为O(N log N),与快速排序相同。空间复杂度为0(N)。这不像Fischer Yates洗牌那样高效,但在我看来,代码明显更短,功能更强大。如果你有一个大数组,你当然应该使用Fischer Yates。如果您有一个包含几百个项目的小数组,您可以这样做。