问题
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