Самый быстрый способ объединить списки, которые имеют общее поле? - PullRequest
2 голосов
/ 29 июня 2011

Я изучаю 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>;    }

Итак, у меня есть несколько таких «событий» из нескольких источников. И мне нужен действительно быстрый способ объединения событий с одним и тем же Именем и Часом, и как только это будет сделано, объедините цены различных вариантов, имеющих одинаковое Имя.

Я думал о том, чтобы получить первый список, а затем выполнить поиск по одному в других списках, и, когда указанное поле совпадает, вернуть новый список, содержащий оба слитых списка.

Я хотел бы знать, есть ли более быстрый способ сделать это, так как производительность будет важна. Я уже видел это Объединение нескольких списков данных по общему идентификатору в F # ... И хотя это было полезно, я прошу лучшее решение с точки зрения производительности. Может быть, использовать любую другую структуру, которая не является списком, или каким-либо другим способом объединить их ... поэтому любой совет будет принят с благодарностью.

Спасибо!

Ответы [ 2 ]

4 голосов
/ 30 июня 2011

Как отметил Даниэль в комментарии, ключевой вопрос заключается в том, насколько лучше нужно сравнивать производительность с решением, основанным на стандартной функции Seq.groupBy?Если вам нужно обработать много данных, на самом деле для этой цели может быть проще использовать какую-то базу данных.

Если вам нужно что-то в ~ 1,7 раза быстрее (или, возможно, больше, в зависимости от количества ядер):-)), тогда вы можете попробовать заменить Seq.groupBy на параллельную версию на основе Parallel LINQ, которая доступна в 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 .В прошлый раз, когда я проверял, производительность была лучше, когда функции были помечены как inline, чего нет в текущем исходном коде, так что вы можете проверить это тоже.

1 голос
/ 30 июня 2011

Я не проверял, но думаю, что это сработает.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...