2016-08-31 7 views
2

私は、セットからランダムな要素の指定された数を選択する関数を書く必要があるプロジェクトに取り組んでいます。その後、これらの要素を後で比較できるように変数にマップします。F#ランダムな要素のセット<string>

私のシナリオでは、任意のセットの5%を選択する必要があります。

let rec randomSet (a:Set<string>) = 
let setLength = (a.Count/100) * 5 

let list = [] 
let rand = System.Random 
if set.Length <> setLength then 
    // some code will go here 
    randomSet setLength eIDS 
else 
    set 

^私のコードを批判してください、私は1週間F#でコーディングしています。

私は再帰的にしようとしましたが、それは間違った方法だと感じています。私は他のメソッドを試しましたが、それらは.take関数を使用しているので、返されるコレクションは毎回同じです。

アイデア?私はセットから1つの要素の後ではない、私はそれにスローされる任意のセットの5%後です。

これは、このように同じ質問ではありません:あなたはそれがあると考えられる場合は、説明してくださいHow can I select a random value from a list using F#

+0

効率場合懸念事項である場合は、[Reservoir Sampling](https://en.wikipedia.org/wiki/Reservoir_sampling)を調べるとよいでしょう。 – kvb

答えて

3

これを行う方法は複数あります。入力の要素数と選択したい項目の数によって、異なる戦略がより効率的になる場合があります。

let data = [| 0 .. 1000 |] 

let rnd = System.Random() 

data 
|> Seq.sortBy (fun _ -> rnd.Next()) 
|> Seq.take 50 

これはランダムに大きな配列のために遅くなることがありシーケンスを(ソートします:

は、おそらく最も簡単な方法は、乱数による入力をソートした後の要素の必要な数を取得するtakeを使用することです)、それからあなたが望む要素の数を正確に取る(Markの解法とは異なり、アイテムの約5%を返す)。

大きなリストから小さい番号を選択する場合は、インデックスをランダムに生成する(重複がないことを確認してから)、インデックスに基づいて直接ルックアップする方がよい場合があります。

+0

ありがとうございます。私は自分のプログラムでコードを試してみましたが、3000個近くの項目ではスピードにあまり影響を及ぼさず、すでに2分の長いランタイムに余分な20秒を追加しました。また、弟は昨日あなたの本を私に買いました。私はそれを読むことを楽しみにしています。 –

3

Set<'a>Seq<'a>を実装しているので、この質問は、あなたがする必要があるだろうすべては、セットをシャッフル最初の5%の要素を取り、そしてセットに戻ってそれを置くことで、実際には、How can I select a random value from a list using F#の複製です。

しかし、それを楽しむために、もう1つの解決策があります。あなたが5%を選択する必要がある場合は、最初にそれを呼び出して倍のtrueわずか5%を返す述語を定義します。

let r = System.Random() 
let fivePercent _ = r.NextDouble() < 0.05 

あなたは今、その述語を使用してセットをフィルタリングすることができます。

let randomlySelectedSubset = stringSet |> Seq.filter fivePercent |> set 
+0

私は申し訳ありませんが、私はそれが同じ質問であるかどうか分かりませんでした。私はF#の初心者です。セットやシークエンスに関する多くの経験はありませんでした。私はあなたが乗っていると言ったことを取って、より多くの時間を彼らに集中させます。 –

+1

ありがとうございます。 –

+0

スピードが問題の場合はこれが勝者です;-) –

関連する問題