EinsL
EinsL

Reputation: 73

Generate two different randoms in F#

I have a F# list and I'm taking two elements of that list.
If the list has 10 elements in it :

let rnd = new Random()
let elem1 = list.Item(rnd.Next(0,9))
let elem2 = list.Item(rnd.Next(0,9))

There is a chance elem1 and elem2 are equal.
I have checked some workarounds and most of them work using a do while, but I don't want to implement a function that may never end in F#.
Is there a way to create a restriction in the random function?

First random  : 0 <= x <= 9 
Second random : 0 <= y <= 9  <> x

Upvotes: 2

Views: 115

Answers (3)

Gus
Gus

Reputation: 26184

A simple solution:

let rnd = new Random()
let ndx1 = rnd.Next(9)
let ndx2 = 
    let x = rnd.Next(8)
    if x < ndx1 then x else x + 1
let elem1, elem2 = list.[ndx1], list.[ndx2]

Another way, using maths and calling the random function once:

let r = Random().Next(9 * 8)
let x = 1 + r + r / 9 
let elem1, elem2 = list.[x / 9], list.[x % 9]

which may be generalised to:

let getTwoElements lst = 
    let c = List.length lst
    let x, y = Math.DivRem(Random().Next(c * (c-1)) * (c+1) / c + 1, c)
    lst.[x], lst.[y]

Upvotes: 3

N_A
N_A

Reputation: 19897

There are lots of way to achieve this. A simple one would be something like this:

open System
open System.Linq
let rnd = new Random()
let elem1 = list.Item(rnd.Next(0,9))
let elem2 = list.Where(fun x->x <> elem1).ElementAt(rnd.Next(0,8))

Upvotes: 0

scrwtp
scrwtp

Reputation: 13577

A more declarative approach, taking into account your comment about points in the image:

let rnd = System.Random()

/// this will build you a list of 10 pairs of indices where a <> b. 
let indices = 
    Seq.initInfinite (fun _ -> rnd.Next(0,10), rnd.Next(0,10))
    |> Seq.filter (fun (a,b) -> a <> b)
    |> Seq.take 10
    |> List.ofSeq

/// map indices into actual points.
let elems =
    let points = list |> Array.ofList
    List.map (fun (a, b) -> points.[a], points.[b]) indices

As a side note, do not use random access on lists. They're not made for that and performance of that is poor. Convert them to an array first.

Upvotes: 3

Related Questions