在我看来,我认为没有必要洗牌整副牌。您只需要确保您的样本是随机的,而不是您的套牌。您可以做的是从前面选择size 数量,然后将采样数组中的每个位置与其中的另一个位置交换。所以,如果你允许替换,你会变得越来越混乱。
function getRandom(length) { return Math.floor(Math.random()*(length)); }
function getRandomSample(array, size) {
var length = array.length;
for(var i = size; i--;) {
var index = getRandom(length);
var temp = array[index];
array[index] = array[i];
array[i] = temp;
}
return array.slice(0, size);
}
本算法只有2*size步骤,如果包含slice方法,则选择随机样本。
更多随机
为了让样本更加随机,我们可以随机选择样本的起点。但是获取样品要贵一些。
function getRandomSample(array, size) {
var length = array.length, start = getRandom(length);
for(var i = size; i--;) {
var index = (start + i)%length, rindex = getRandom(length);
var temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
}
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
return sample;
}
使这更加随机的原因是,当您总是对前面的项目进行洗牌时,如果采样数组很大而样本很小,您往往不会经常在样本中得到它们。如果数组不应该始终相同,这将不是问题。所以,这个方法所做的就是改变这个打乱区域开始的位置。
不可更换
为了不必复制采样数组并且不用担心替换,您可以执行以下操作,但它确实为您提供 3*size 与 2*size。
function getRandomSample(array, size) {
var length = array.length, swaps = [], i = size, temp;
while(i--) {
var rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[i];
array[i] = temp;
swaps.push({ from: i, to: rindex });
}
var sample = array.slice(0, size);
// Put everything back.
i = size;
while(i--) {
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
}
return sample;
}
无替换,更多随机
将提供更多随机样本的算法应用于无替换函数:
function getRandomSample(array, size) {
var length = array.length, start = getRandom(length),
swaps = [], i = size, temp;
while(i--) {
var index = (start + i)%length, rindex = getRandom(length);
temp = array[rindex];
array[rindex] = array[index];
array[index] = temp;
swaps.push({ from: index, to: rindex });
}
var end = start + size, sample = array.slice(start, end);
if(end > length)
sample = sample.concat(array.slice(0, end - length));
// Put everything back.
i = size;
while(i--) {
var pop = swaps.pop();
temp = array[pop.from];
array[pop.from] = array[pop.to];
array[pop.to] = temp;
}
return sample;
}
更快...
与所有这些帖子一样,它使用了 Fisher-Yates Shuffle。但是,我删除了复制数组的开销。
function getRandomSample(array, size) {
var r, i = array.length, end = i - size, temp, swaps = getRandomSample.swaps;
while (i-- > end) {
r = getRandom(i + 1);
temp = array[r];
array[r] = array[i];
array[i] = temp;
swaps.push(i);
swaps.push(r);
}
var sample = array.slice(end);
while(size--) {
i = swaps.pop();
r = swaps.pop();
temp = array[i];
array[i] = array[r];
array[r] = temp;
}
return sample;
}
getRandomSample.swaps = [];