Reputation: 122450
I'm trying to shuffle the elements of a list:
(* 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
However, this just always returns items
in the same order, because:
> 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)]
Why is System.Random().Next()
always returning the same value in each call? Is it because the successive calls are chronologically too close together? Or am I misuing the API in some other way?
(Note: this answer works fine for me, but I'm curious about why this behavior shows up.)
Upvotes: 3
Views: 718
Reputation: 1153
One thing to keep in mind is that you are not generating a sequence of numbers from a random number generator, but instead are creating a sequence of random number generators and generating the first random number of each of those.
Remember that System.Random().Next()
is shorthand for (new System.Random()).Next()
, so you create a new System.Random object on each iteration using the default constructor of Random. As mentioned in the other answers, that default constructor uses a coarse value of the current time as the initial seed for the RNG, so when called in quick succession, will essentially recreate the same RNG every time (which will generate the same number on its first and only invocation).
The solution is to create only one System.Random object and reuse that:
> 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)]
Upvotes: 4
Reputation: 180917
It's best explained by the manual of System.Random()'s default constructor;
The default seed value is derived from the system clock and has finite resolution. As a result, different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers.
Upvotes: 9
Reputation: 47904
It works this way because you're using the same seed value every time. That's why it's important to make successive calls to the same instance of Random
.
Upvotes: 3