I would like to create a collection of binaries with n
set bits and total length should be between n and 31
; also those set bits should be randomly positioned. For example if n = 3
, then [1;0;1;0;1], [1;0;0;1;1;]
and [1;1;1;0;0]
should all be possible with equal chance.
Below is my implementation and any feedback is welcome.
/// <summary>
/// Create a random collection of binaries, between n and 31 elements, with n bits are set.
/// The set positions should be random too.
/// </summary>
/// <param name="n">The number of set bits in the collection; must be positive and less than 32</param>
let createRandomBinary (n : int) =
if n > 31 || n < 0 then ArgumentException("invalid input: must be positive and less than 32", "n") |> raise
let ran = new Random()
let mutable totalLength = ran.Next(n, 32) // [n, 32)
match totalLength with
| x when x = n -> Array.init n (fun _-> 1) // all bits are set case
| _ -> let res : int array = Array.zeroCreate totalLength // initialise a result with all 0s.
let indices = ResizeArray(seq{0..totalLength - 1})
let mutable counter = n
let rec shuffle = function
| 0 -> res // all n 1s have been set randomly so return the result
| _ -> counter <- counter - 1
let i = ran.Next(0, totalLength) // randomly pick an index and set to 1
res.[indices.[i]] <- 1
indices.RemoveAt(i) // remove the chosen index so it won't be set twice
totalLength <- totalLength - 1 // decrease the length for next random index pick
shuffle counter
shuffle counter