How to Generate A Specific Number of Random Indices for Array Element Removal F#

馋奶兔 提交于 2020-12-07 13:36:39

问题


So sCount is the number of elements in the source array, iCount is the number of elements I want to remove.

let indices = Array.init iCount (fun _ -> rng.Next sCount) |> Seq.distinct |> Seq.toArray |> Array.sort

The problem with the method above is that I need to specifically remove iCount indices, and this doesn't guarantee that.

I've tried stuff like

while indices.Count < iCount do
    let x = rng.Next sCount
    if not (indices.Contains x) then
        indices <- indices.Add x

And a few other similar things...

Every way I've tried has been extremely slow though - I'm dealing with source arrays of sizes up to 20 million elements.


回答1:


What you're doing should be fine if you need a set of indices of negligible size compared to the array. Otherwise, consider doing a variation of a Knuth-Fisher-Yates shuffle to get the first i elements in a random permutation of 1 .. n:

let rndSubset i n =
    let arr = Array.zeroCreate i
    arr.[0] <- 0
    for j in 1 .. n-1 do
        let ind = rnd.Next(j+1)
        if j < i then arr.[j] <- arr.[ind]
        if ind < i then arr.[ind] <- j
    arr



回答2:


I won't give you F# code for this (because I don't know F#...), but I'll describe the approach/algorithm that you should use.

Basically, what you want to do is pick n random elements of a given list list. This can be done in pseudocode:

chosen = []
n times:
    index = rng.upto(list.length)
    elem = list.at(index)
    list.remove-at(index)
    chosen.add(elem)

Your list variable should be populated with all possible indices in the source list, and then when you pick n random values from that list of indices, you have random, distinct indices that you can do whatever you want with, including printing values, removing values, knocking yourself out with values, etc...




回答3:


is iCount closer to the size of the array or closer to 0? That will change the algorithm which you will use.

If closer to 0, then keep track of the previously generated numbers and check if additional numbers have already been generated.

If closer to the size of the array then use the method as described by @feralin




回答4:


let getRandomNumbers =
  let rand = Random()
  fun max count -> 
    Seq.initInfinite (fun _ -> rand.Next(max))
    |> Seq.distinct
    |> Seq.take count

let indices = Array.init 100 id
let numToRemove = 10

let indicesToRemove = getRandomNumbers (indices.Length - 1) numToRemove |> Seq.toList
> val indicesToRemove : int list = [32; 38; 26; 51; 91; 43; 92; 94; 18; 35]


来源:https://stackoverflow.com/questions/17455909/how-to-generate-a-specific-number-of-random-indices-for-array-element-removal-f

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!