是否可以使用Array.prototype.reduce创建一个线性随机选择的数组?

时间:2016-02-12 22:36:33

标签: javascript arrays reduce random-sample

使用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;
})}
`);

在对此进行一些测试之后,分布似乎偏向较低的指数(也就是说更频繁地选择较高的指数)。

1 个答案:

答案 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;
})}
`);

这是一个测试,证明它确实以统一的概率返回每个字母:

&#13;
&#13;
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;
&#13;
&#13;