使用Array.prototype.reduce
(或Array.prototype.reduceRight
)的签名,是否可以从数组中选择一个项目,所有索引的概率相等?这是我的尝试:
document.write(`
${[...'abcdefghijklmnopqrstuvwxyz'].reduce(function(last, next, index, array) {
if (Math.random() > index / array.length) {
return next;
}
return last;
})}
`);
在对此进行一些测试之后,分布似乎偏向较低的指数(也就是说更频繁地选择较高的指数)。
答案 0 :(得分:5)
您可以使用reservoir sampling:始终选择第一个元素,然后在遍历数组时,使用k th 替换当前选择的项目(基于1)索引)项目,概率为1/k
。这将给你一个统一的概率:
document.write(`
${[...'abcdefghijklmnopqrstuvwxyz'].reduce(function(last, next, index, array) {
if ( Math.random()*(index + 1) <= 1 ) {
return next;
}
return last;
})}
`);
这是一个测试,证明它确实以统一的概率返回每个字母:
var results = {};
for ( var i = 0; i < 100000; i++ ) {
var choice = [...'abcdefghijklmnopqrstuvwxyz'].reduce(function(last, next, index, array) {
if ( Math.random()*(index + 1) <= 1 ) {
return next;
}
return last;
} );
results[ choice ] = (results[ choice ] || 0) + 1;
}
document.body.innerHTML = '<pre>' + JSON.stringify( results, '\t' ) + '</pre>';
&#13;