2011-06-29 13 views
2

私はF#を学んでいます。私は実際にpu理論にオッズ比較サービス(ala www.bestbetting.com)をやっています。共通のフィールドを持つリストをマージする最速の方法は?

type price = { Bookie : string; Odds : float32; } 

type selection = { 
    Prices : list<price>; 
    Name : string; 
    } 

type event = { Name : string; Hour : DateTime; Sport : string; Selections : list<selection>; } 

だから、私はいくつかのソースから来るこれらの「イベント」のいくつかを持っている: は、これまでのところ私は、次のデータ構造を持っています。そして、同じ名前と時間でイベントをマージする本当に速い方法が必要になり、同じ名前の異なる選択肢の価格をマージすると、それが完了します。

私は最初のリストを取得した後、他のリストに対して1つずつ検索を行い、指定されたフィールドが一致すると、両方のリストを含む新しいリストを返します。

私はパフォーマンスが重要であるため、これを行うより速い方法があるかどうかを知りたいと思います。私はすでにこれを見てきましたMerge multiple lists of data together by common ID in F# ...それは役に立ちましたが、私は最高のパフォーマンスワイズのソリューションを求めています。おそらく他の構造を使ってリストや他のマージ方法ではないので、アドバイスをいただければ幸いです。

ありがとうございます!

+0

構文をハイライト表示するように、ブロッククォートをコードに変更しました。 –

+0

ところで、投稿する前にこのhttp://stackoverflow.com/questions/4787226/merge-multiple-lists-of-data-together-by-common-id-in-fを見ましたが...私は最高のパフォーマンスワイズのソリューションを求めています。ありがとう。 –

+0

@ジャコボ:それを示すために質問を編集する必要があると思います.. –

答えて

4

ダニエルはコメントで述べたように、重要な問題は、標準Seq.groupBy機能に基づくソリューションと比較するパフォーマンスの必要性をどうするかより良い、ですか?処理するデータが大量にある場合は、実際にこの目的のためにデータベースを使用するほうが簡単かもしれません。

〜1.7倍(またはコアの数に応じておそらく多くの場合):-)が必要な場合は、Seq.groupByをF#PowerPackで利用可能なパラレルLINQに基づいてパラレルバージョンに置き換えることができます。 PSeq.groupBy(およびその他のPSeq機能)を使用して、このような何か書くことができます。

#r "FSharp.PowerPack.Parallel.Seq.dll" 
open Microsoft.FSharp.Collections 

// Takes a collection of events and merges prices of events with the same name/hour 
let mergeEvents (events:seq<event>) = 
    events 
    |> PSeq.groupBy (fun evt -> evt.Name, evt.Hour) 
    |> PSeq.map (fun ((name, hour), events) -> 
     // Merge prices of all events in the group with the same Selections.Name 
     let selections = 
     events 
     |> PSeq.collect (fun evt -> evt.Selections) 
     |> PSeq.groupBy (fun sel -> sel.Name) 
     |> PSeq.map (fun (name, sels) -> 
      { Name = name 
       Prices = sels |> Seq.collect (fun s -> s.Prices) |> List.ofSeq }) 
     |> PSeq.toList 
     // Build new Event as the result - since we're grouping just using 
     // name & hour, I'm using the first available 'Sport' value 
     // (which may not make sense) 
     { Name = name 
     Hour = hour 
     Sport = (Seq.head events).Sport 
     Selections = selections }) 
    |> PSeq.toList 

を私は、このバージョンのパフォーマンスをテストしていないが、私はそれがより速くなるべきだと考えています。また、アセンブリ全体を参照する必要はありません。いくつかの関連する機能のソースをコピーすることができます。PowerPack source code。前回チェックしたときに、機能がinlineとマークされたときの方がパフォーマンスが良かった。これは現在のソースコードでは当てはまりません。

+0

こんにちは、お早めにお返事できなかったのは残念です。非常にストレスの多い日でした。 私はそれを言及していたはずです...私はより速い方法を望んでいただけでなく、コードの可読性を重視していました。私はF#の初心者なので、まだ多くの場所で参照されていますが、F#Power Pack Libraryはまだ使用していません。 学習の過程で非常に貴重な洞察であるので、サンプルコードを入力する時間をとってくれてありがとうございました。 –

+0

ところでトマスは、これは場所ではありませんが、F#についての素晴らしい本に感謝します。あなたとドン・シムズは私が同じスタイルで違ったスタイルを見つけたので、私が使っているものです。あなたの本をたどることは非常に喜ばしいことです。今私はその仕事に専念する時間を増やすことを望みました。乾杯。 –

+0

@Jacobo - この本の素晴らしい言葉をありがとう!答えは役に立つと思いますが(いつものように並列プログラミング)、パフォーマンスを測定して実際に役立つかどうかを確認する必要があります。 –

1

私はそれをテストしていませんが、これはうまくいくと思います。

let events = List.init 10 (fun _ -> Unchecked.defaultof<event>) //TODO: initialize to something meaningful 

for ((name, hour), evts) in (events |> Seq.groupBy (fun e -> e.Name, e.Hour)) do 
    printfn "Name: %s, Hour: %A" name hour 
    let prices = 
    seq { 
     for e in evts do 
     for s in e.Selections do 
      for p in s.Prices do 
      yield s.Name, p 
    } 
    |> Seq.groupBy fst 

    for (selectionName, p) in prices do 
    printfn " Selection Name: %s" selectionName 
    for (_, price) in p do 
     printfn " %A" price 
+0

こんにちはダニエルとサンプルコードを書く時間を割いていただきありがとうございます。私はこの言語に慣れていないので、何かが欠落している可能性がありますが、これは上記のコードの並列PSeq.GroupByよりも速くなければならない理由は何ですか?私はコードが何をしているかを追うと思うが、それが速くなる理由はない。私が知り得ないことは何でも?私はそれを試し、私の好奇心を満たすだけの比較をします。助けてくれてありがとう。 –

+0

@Jacobo:いいえ、これはパラレルバージョンより速くする必要はありませんが、パラレル化にはコストがかかりますが、場合によってはメリットが無効になることもあります。トマスが言ったように、確かに知る唯一の方法は尺度です。 – Daniel

関連する問題