3

I have been searching other questions, where users would instantiate many System.Random()'s within a loop or method and therefore create many of the same randoms from the same clock. But here I have one instantiated System.Random() but when I try to use it to create multiple random number lists, they are all the same.

module Scripts =
let rnd = System.Random() 

let getRandom36 =
    let rec generate (l : list<int>) =
        match l.Length with
        |8 -> l
        |_ -> let number = rnd.Next 38
              if(List.exists(fun elem -> elem=number) l) then generate l else generate (number::l)
    List.sort(generate List.empty)

let myseq = Seq.init 4 (fun _ -> getRandom36)

The important part is not really how the code inside getRandom36 works, I have been tampering with it to work in different ways, but I keep getting lists that look the same when calling myseq;;.

myseq;;
val it : seq<int list> =
  seq
    [[2; 8; 10; 11; 18; 21; 22; 35]; [2; 8; 10; 11; 18; 21; 22; 35];
     [2; 8; 10; 11; 18; 21; 22; 35]; [2; 8; 10; 11; 18; 21; 22; 35]; ...]

Any ideas why? I mean shouldn't the rnd.Next be different each time since no new instance of rnd is made for each iteration.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Copperström
  • 359
  • 2
  • 6

3 Answers3

5

getRandom36 is a value not a function. Can be fixed like below:

let rnd = System.Random() 

let getRandom36 _ =
    let rec generate (l : list<int>) =
        match l.Length with
        |8 -> l
        |_ -> let number = rnd.Next 38
              if(List.exists(fun elem -> elem=number) l) then generate l else generate (number::l)
    List.sort(generate List.empty)

let myseq = Seq.init 4 getRandom36
2

The problem is that getRandom36 is a value, not a function. It gets evaluated once, then always returns the same list. Turn it into a function, and it should work correctly:

module Scripts =

    let rnd = System.Random ()

    let getRandom36 () =
        let rec generate (l : _ list) =
            match l.Length with
            | 8 -> l
            | _ -> let number = rnd.Next 38
                   if List.exists (fun elem -> elem = number) l
                   then l else (number :: l)
                   |> generate
        List.sort (generate [])

    let myseq = Seq.init 4 (fun _ -> getRandom36 ())
dumetrulo
  • 1,993
  • 9
  • 11
0

While the OP might be looking for a very specific solution using recursion, there are easier/faster ways to generate random numbers by using MathDotNet or even the stock System.Random.

For example:

#load @"..\..\FSLAB\packages\FsLab\FsLab.fsx"

open MathNet.Numerics.LinearAlgebra
open MathNet.Numerics.Distributions
open MathNet.Numerics.Random

let rng = Random.shared
Array2D.init<int> 4 8 (fun i j -> rng.Next(38)) 

Or:

[for i in 1..4 -> List.init 8 (fun x -> rnd.Next(38))]

And there are functions like .NextInt32s that will fill an already existing array for example:

let fillArray (x:int []) = rng.NextInt32s(x,0,38)
let xs = [|for i in 1..4 -> Array.zeroCreate<int> 8|]
xs |> Array.map (fun x -> fillArray(x))
s952163
  • 6,276
  • 4
  • 23
  • 47