2011-06-29 30 views
2

我正在学习F#,我正在做和赔率比较服务(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>; } 

所以,我有几个这样的“事件”从多个来源来的。而且我需要一种非常快速的方式来合并具有相同名称和小时的事件,并且一旦完成合并具有相同名称的不同选择的价格。

我想过要获得第一个列表,然后在其他列表上做一个一个的搜索,以及何时指定的字段匹配返回一个包含两个列表合并的新列表。

我想知道是否有一个更快的方法来做到这一点,因为性能会很重要。我已经看到这个Merge multiple lists of data together by common ID in F# ...虽然这很有帮助,但我正在寻求最佳的性能方案。也许使用任何其他结构,它不是一个列表或其他合并方式...所以任何建议将不胜感激。

谢谢!

+0

我将blockquote更改为代码,以便语法突出显示。 –

+0

顺便说一下,我发布之前已经看过这个http://stackoverflow.com/questions/4787226/merge-multiple-lists-of-data-together-by-common-id-in-f ...尽管是有帮助的,我要求最好的性能方面的解决方案。谢谢。 –

+0

@Jacobo:我认为你应该编辑这个问题来表明.. –

回答

4

丹尼尔·注释中,关键的问题是,如何更好地就性能需要进行比较,以基于标准Seq.groupBy功能的解决方案?如果你有很多数据需要处理,那么为此目的使用某些数据库可能会更容易。如果你只需要1.7倍的速度(或者更多,取决于核心数量:-)),那么你可以尝试用基于并行LINQ的并行版本代替Seq.groupBy,该版本在F#PowerPack中可用。使用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#的伟大书籍。你和Don Syme是我使用的,因为我发现它们同样很棒,风格不同。非常高兴地跟随你的书,我只是希望我现在可以有更多的时间专注于这项任务。干杯。 –

+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

相关问题