質問
F#のセットからランダムサブセットを取得するエレガントな方法を考えようとしています
これについて何か考えはありますか?
おそらくこれはうまくいくでしょう:私たちは2のセットを持っていると言いますバツ 要素とY要素のサブセットを選択する必要があります。次に、正確にy 2を含むxサイズのビット乱数を生成できればn パワーYホールが入ったランダムマスクが効果的にあります。この制約を満たす最初のものが得られるまで、新しい乱数を生成し続けることができますが、より良い方法はありますか?
解決
アレイに変換したくない場合は、このようなことをすることができます。これはo(n*m)で、mはセットのサイズです。
open System
let rnd = Random(0);
let set = Array.init 10 (fun i -> i) |> Set.of_array
let randomSubSet n set =
seq {
let i = set |> Set.to_seq |> Seq.nth (rnd.Next(set.Count))
yield i
yield! set |> Set.remove i
}
|> Seq.take n
|> Set.of_seq
let result = set |> randomSubSet 3
for x in result do
printfn "%A" x
他のヒント
@johannesrosselに同意します。 f#shuffle-an-arrayアルゴリズムがあります ここ 適切に変更できます。セットを配列に変換し、新しいサブセットに十分なランダム要素を選択するまでループします。
F#とそこでエレガントと見なされるかもしれないものを本当によく把握していないので、要素のリストでシャッフルをして最初のものを選択できます y。 a フィッシャー - シャッフル あなたもシャッフルする必要があるので、この点であなたを助けます y 要素。
RNDはサブセット関数から外れている必要があります。
let rnd = new Random()
let rec subset xs =
let removeAt n xs = ( Seq.nth (n-1) xs, Seq.append (Seq.take (n-1) xs) (Seq.skip n xs) )
match xs with
| [] -> []
| _ -> let (rem, left) = removeAt (rnd.Next( List.length xs ) + 1) xs
let next = subset (List.of_seq left)
if rnd.Next(2) = 0 then rem :: next else next
任意のサイズのランダムサブセットを意味しますか?
特定のサイズのランダムサブセットの場合、ここに非常にエレガントな答えがあります:
ここでは擬似コードにあります:
RandomKSubset(list, k):
n = len(list)
needed = k
result = {}
for i = 0 to n:
if rand() < needed / (n-i)
push(list[i], result)
needed--
return result
seq.foldを使用して、怠zyな評価ランダムサブセットを使用して構築します。
let rnd = new Random()
let subset2 xs = let insertAt n xs x = Seq.concat [Seq.take n xs; seq [x]; Seq.skip n xs]
let randomInsert xs = insertAt (rnd.Next( (Seq.length xs) + 1 )) xs
xs |> Seq.fold randomInsert Seq.empty |> Seq.take (rnd.Next( Seq.length xs ) + 1)
所属していません StackOverflow