2017-02-26 39 views
5

我想出這個簡單的算法(轉換的元組的列表鍵的地圖集合列表),我需要在我的F#代碼:此算法已有高階函數嗎?

let MergeIntoMap<'K,'V when 'K: comparison>(from: seq<'K*'V>): Map<'K,seq<'V>>= 
    let keys = from.Select(fun (k,v) -> k) 
    let keyValuePairs = seq { 
     for key in keys do 
      let valsForKey = from.Where(fun (k,v) -> key = k).Select(fun (k,v) -> v) |> seq 
      yield key,valsForKey 
    } 
    keyValuePairs |> Map.ofSeq 

例輸入:

[ ("a", 1); ("b", 2), ("a", 3) ] 

輸出:

dict [ ("a", [1; 3]), ("b", [2]) ] 

我在想這一定是已經存在於BCL或F#的高階函數集中的東西嗎?如果是的話,有人可以參考我嗎?因爲我敢肯定,我的代碼是不是很有效,因爲它是...

+0

@FoggyFinder:更新 – ympostor

回答

4

看來你想要得到的東西一樣,

let toGroupMap x = 
    x 
    |> Seq.groupBy fst 
    |> Seq.map 
     (fun (k,v) -> k, v |> Seq.map snd |> Seq.toArray) 
    |> Map.ofSeq 

FSI:

val toGroupMap : x:seq<'a * 'b> -> Map<'a,'b []> when 'a : comparison 
val input : (string * int) list = [("a", 1); ("b", 2); ("a", 3)] 
val output : Map<string,int []> = map [("a", [|1; 3|]); ("b", [|2|])] 

編輯

正如在評論中寫着Fyodor Soikin,那裏是一個擴展方法ToLookup,它可能會做你所需要的。

open System.Linq 

let output = input.ToLookup(fst, snd) 

您可以閱讀here約ILookup和IDictionary的接口之間的差異

+0

所以沒有高階函數已經這樣做了?爲什麼你的解決方案比我的更好?你是否建議你更有效率? – ympostor

+5

這個代碼比你原來的算法更好看。首先,'Seq.groupBy'是O(N),而你的是O(N^2),因爲它貫穿每個鍵的整個'from'序列。其次,Foggy Finder的代碼看起來更加習慣。也就是說,作爲一名經驗豐富的F#編碼員,我可以閱讀它並立即看到它在做什麼。鑑於你使用LINQ的代碼更多的是類C#和更加不透明的,而且要花費我相當長的時間才能看到它的功能。更容易閱讀的代碼可以更好地理解程序,從而導致長遠而言更少的錯誤。 – rmunn

+5

等一下,是不是'.ToLookup'完成那件事? –