Search code examples
functional-programmingf#fscheck

Best way to generate random indices into an array?


Good afternoon. I have a set of values from which I'd like to draw a random subset.

My first thought was this:

let getRandomIndices size count =
  if size >= count then
    let r = System.Random()
    r.GetValues(0,size) |> Seq.take count |> Seq.toList
  else
    [0..size-1]

However, r.GetValues(0,size) may generate the same value multiple times. How can I get distinct values? My first thought is to repeatedly store indexes into a set until the set holds the desired number of elements? But this seems too procedural/not-functional enough? Is there a better way?

Or should I start with [0..size-1] and remove random elements from it until it holds the desired number indices?

I'm not really looking for the most efficient approach, but the most functional one. I am struggling to better grok the functional mindset.


Solution

  • If you sort a list of all the indices randomly, you can just take the first count number of elements in the list.

    let getRandomIndices size count =
      if size >= count then
        let r = System.Random()
        [0..size-1] |> List.sortBy (fun _ -> r.Next()) |> List.take count
      else
        [0..size-1]