我正在学习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 :(得分:4)
丹尼尔在评论中提到,关键问题是,与基于标准Seq.groupBy
功能的解决方案相比,性能需要更好吗?如果要处理大量数据,那么为此目的使用某些数据库实际上可能更容易。
如果你只需要1.7倍的速度(或者可能更多,取决于内核的数量:-)),那么你可以尝试用基于F#中提供的Parallel LINQ的并行版本替换Seq.groupBy
动力单元。使用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
时,性能会更好,这在当前源代码中并非如此,所以您可能也想检查它。
答案 1 :(得分: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