2012-08-15 41 views
3

我想洗牌的列表的元素相同的结果:System.Random()和Next()返回

(* Returns a list with the same elements as the original but in randomized order *) 
let shuffle items = 
    items 
    |> List.map (fun x -> (x, System.Random().Next())) 
    |> List.sortBy snd 
    |> List.map fst 

然而,这只是总是以相同的顺序返回items,因为:

> List.map (fun x -> x, System.Random().Next()) [1; 2; 3];; 
val it : (int * int) list = [(1, 728974863); (2, 728974863); (3, 728974863)] 

> List.map (fun x -> x, System.Random().Next()) [1; 2; 3];; 
val it : (int * int) list = 
    [(1, 1768690982); (2, 1768690982); (3, 1768690982)] 

> List.map (fun x -> x, System.Random().Next()) [1; 2; 3];; 
val it : (int * int) list = [(1, 262031538); (2, 262031538); (3, 262031538)] 

为什么System.Random().Next()总是在每个调用中返回相同的值?是否因为连续的呼叫在时间上过于靠近?或者我以其他方式误用API?

(注:此answer工作正常,我,但我很好奇,为什么这种行为显示出来)

回答

9

最好由System.Random()'s default constructor手册解释;

默认种子值来自系统时钟,并具有有限的 分辨率。因此,通过调用默认构造函数在 中创建的不同Random对象将具有相同的默认种子值,因此将产生相同的 组随机数。

3

它,因为你每次使用相同的种子值以这种方式工作。这就是为什么连续调用Random的同一个实例很重要。

4

要记住的一件事是,您不是从随机数生成器生成一个数字序列,而是创建一个随机数生成器的序列并生成每个数的第一个随机数。

请记住,System.Random().Next()(new System.Random()).Next()的缩写,因此您使用Random的默认构造函数在每次迭代中创建一个新的System.Random对象。正如其他答案中提到的那样,该默认构造函数使用当前时间的粗略值作为RNG的初始种子,因此,当快速连续调用时,将基本上每次都重新创建相同的RNG(它将在其上生成相同的数字第一个也是唯一的调用)。

的解决方案是只创建一个System.Random对象和重新使用:

> let rng = new System.Random() in List.map (fun x -> x, rng.Next()) [1; 2; 3];; 
val it : (int * int) list = [(1, 483259737); (2, 719806274); (3, 1951956175)] 
相关问题