我有一个这样的数组:
var arr1 = ["a", "b", "c", "d"];
我如何随机化/打乱它?
我有一个这样的数组:
var arr1 = ["a", "b", "c", "d"];
我如何随机化/打乱它?
当前回答
从理论的角度来看,在我看来,最优雅的方法是得到一个介于0和n之间的随机数-并计算从{0,1,…,n!-1}到(0,1、2,…,n-1)的所有置换的一对一映射。只要你能使用一个足够可靠的(伪)随机发生器来获得这样一个数字而没有任何明显的偏差,你就有足够的信息来实现你想要的,而不需要其他几个随机数。
当使用IEEE754双精度浮点数计算时,您可以期望随机生成器提供大约15个小数。既然你有15岁=1307674368000(带13位数字),您可以对最多包含15个元素的数组使用以下函数,并假设最多包含14个元素的阵列不会有明显的偏差。如果您正在处理一个固定大小的问题,需要多次计算该洗牌操作,您可能需要尝试以下代码,因为它只使用Math.random一次(但它涉及多次复制操作),因此可能比其他代码更快。
下面的函数不会被使用,但我还是给出了它;它根据此消息中使用的一对一映射(枚举排列时最自然的映射)返回给定排列(0,1,2,…,n-1)的索引;它打算与多达16个元件一起工作:
function permIndex(p) {
var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000];
var tail = [];
var i;
if (p.length == 0) return 0;
for(i=1;i<(p.length);i++) {
if (p[i] > p[0]) tail.push(p[i]-1);
else tail.push(p[i]);
}
return p[0] * fact[p.length-1] + permIndex(tail);
}
上一个函数的倒数(您自己的问题需要)如下:;它打算与多达16个元件一起工作;它返回(0,1,2,…,s-1)的n阶排列:
function permNth(n, s) {
var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000];
var i, j;
var p = [];
var q = [];
for(i=0;i<s;i++) p.push(i);
for(i=s-1; i>=0; i--) {
j = Math.floor(n / fact[i]);
n -= j*fact[i];
q.push(p[j]);
for(;j<i;j++) p[j]=p[j+1];
}
return q;
}
现在,你想要的只是:
function shuffle(p) {
var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000];
return permNth(Math.floor(Math.random()*fact[p.length]), p.length).map(
function(i) { return p[i]; });
}
它应该适用于多达16个元素,但有一点理论偏差(尽管从实际角度看不明显);它可以被视为完全可用于15个元件;对于包含少于14个元素的数组,您可以放心地认为绝对没有偏差。
其他回答
使用Ramda的功能解决方案。
const {map, compose, sortBy, prop} = require('ramda')
const shuffle = compose(
map(prop('v')),
sortBy(prop('i')),
map(v => ({v, i: Math.random()}))
)
shuffle([1,2,3,4,5,6,7])
事实上的无偏洗牌算法是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;
}
通过使用洗牌阵列模块,您可以洗牌您的阵列。这里有一个简单的代码。
var shuffle = require('shuffle-array'),
//collection = [1,2,3,4,5];
collection = ["a","b","c","d","e"];
shuffle(collection);
console.log(collection);
希望这有帮助。
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;
}