如何让随机选择更...随机

How to make random selection more... random

我有一个简单的 JavaScript,它通过从多个其他字符串列表中选择“随机”* 来构建随机字符串。当 运行 脚本重复时,我注意到 很多 重复,我试图理解为什么。我知道在这种情况下没有 真正 随机这样的东西。但我看到的重复并不微妙。我的列表每个都有 20-30 个项目,我经常看到同一个字符串连续出现两次和三次。

这里是有关如何从单个列表中选择字符串的相关代码。

function(list) {
    return list[Math.floor(Math.random()*list.length)];
}

脚本连续多次调用此函数,将不同的列表作为参数传递。

这是我的代码有问题吗?或者可能有什么东西被缓存了?

(注意:这不是为了安全!切勿用这种方式代替正确的加密)

我试了一下你的代码如下:

list = ['one','two','three','four','five','six','seven','eight','nine','ten']

for (i=0;i<10;i++) {
  console.log(list[Math.floor(Math.random()*list.length)])
}

// RUN ONE
// 'two'
// 'six'
// 'eight'
// 'one'
// 'eight'
// 'two'
// 'two'
// 'two'
// 'ten'
// 'six'

// RUN TWO
// 'four'
// 'seven'
// 'nine'
// 'one'
// 'six'
// 'six'
// 'eight'
// 'two'
// 'nine'
// 'three'

有趣的是有多少重复,但我认为你应该期待 一些。有没有可能你真正要找的是洗牌?如果是这样,您可能会发现这个问题的答案很有用:How to randomize (shuffle) a JavaScript array?

获取随机元素的代码很多。我知道,但这只是一个想法,可能会帮助你取得更好的结果。

所以我主要是将三个预览随机数保存在一个数组中,然后使用条件来查看是否必须生成新的随机数。

在随机性中 two/three/four/... 连续相同的数字总是可能的,所以永远不要避免拥有它们。此代码还将给出连续的相同元素,但要少得多。

const list = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

function getRand(){ 
  return Math.floor(Math.random() * list.length)
}

let previews = [null, null, null]
let n = null

list.forEach((el) => {
  n = getRand()
  
  if(previews[0] === n || previews[1] === n || previews[2] === n){
     n = getRand()
     previews = [n, ...previews]
   }
   else {
     previews = [n, ...previews]
   }
   console.log(list[n])
})

几个答案和评论让我 second-guess 我看到的结果是否真的令人惊讶。对于包含 30 个项目的列表,连续三次获得特定项目的几率是 1/(303030)。但是获得任意项3次的几率要大得多。

我认为我的代码实际上非常接近著名的 Fisher-Yates 洗牌算法: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

所以也许我的代码实际上按预期运行?

您的代码是正确的。人类认为的随机性与随机性实际看起来有很大区别。听起来您可能正在考虑将句子中任何位置的任何连续重复单词视为相同的结果。真的不是;您将大量不同的结果组合在一起,称之为单一的“频繁”结果。试着先挑一个词,看看这个词出现在你句子的最后三个词需要多长时间。

如果您仍然对更强的随机数感兴趣,可以查看 rando.js or random.org,但要知道它们会表现出相同的行为 - 这是一件好事。