Frage

Ich versuche mir eine elegante Art zu denken, eine zufällige Teilmenge von einem Set in F# zu erhalten

Irgendwelche Gedanken dazu?

Vielleicht würde das funktionieren: Angenommen, wir haben einen Satz von 2x Elemente und wir müssen eine Untergruppe von Y -Elementen auswählen. Wenn wir dann eine X -Größe -Zufallszahl von X -Größe generieren könnten, die genau Y 2 enthältn Kräfte, die wir effektiv eine zufällige Maske mit Y -Löchern haben. Wir könnten weiterhin neue Zufallszahlen generieren, bis wir den ersten bekommen, der diese Einschränkung befriedigt, aber gibt es einen besseren Weg?

War es hilfreich?

Lösung

Wenn Sie nicht in ein Array konvertieren möchten, können Sie so etwas tun. Dies ist o (n*m), wobei m die Größe des Satzes hat.

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    

Andere Tipps

Stimmen Sie @johannesrossel zu. Es gibt einen F# Shuffle-Anarray-Algorithmus hier Sie können sich angemessen ändern. Konvertieren Sie das Set in ein Array und schalten Sie dann auf, bis Sie genügend zufällige Elemente für die neue Teilmenge ausgewählt haben.

Wenn Sie kein wirklich gutes Verständnis für F# haben und was dort als elegant angesehen werden könnte y. EIN Fisher-yates Shuffle Hilft Ihnen in dieser Hinsicht sogar, da Sie auch nur mischen müssen y Elemente.

RND muss außerhalb der Untergruppe sein.

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

Meinst du eine zufällige Teilmenge einer Größe?

Für den Fall einer zufälligen Teilmenge einer bestimmten Größe gibt es hier eine sehr elegante Antwort:

Wählen Sie n zufällige Elemente aus einer Liste ausu003CT> in C#

Hier ist es in Pseudocode:

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

Verwenden von seq.fold zum Konstrukt mit einer faulen Bewertung zufälliger Untereinsatz:

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)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top