2017-10-16 142 views
2

一個時髦的標題也許,但我遇到了下列問題:給定一個(A * B)列表,返回(A * B列表)名單

鑑於(a * b) list類型的列表,我想創建一個類型爲(a * b list) list的新列表。舉例:

給定列表let testList = [(1,"c");(2,"a");(1,"b")],我的函數應該返回[(1, ["c";"b"]; (2, ["a"])]

我有以下的,但我對如何繼續有點卡住:

let rec toRel xs = 
    match xs with 
    | (a,b)::rest -> (a,[b])::toRel rest 
    | _   -> [] 
+1

您可以使用''List.groupBy'' – Gustavo

回答

8

您可以使用內置的功能List.groupBy然後映射刪除多餘的關鍵:

testList |> List.groupBy fst |> List.map (fun (k,v) -> (k, List.map snd v)) 

// val it : (int * string list) list = [(1, ["c"; "b"]); (2, ["a"])] 

否則,如果你想繼續比賽,你可以做這樣的事情:

let toRel x = 
    let rec loop acc xs = 
     match xs with 
     | (k, b) :: rest -> 
      let acc = 
       match Map.tryFind k acc with 
       | Some v -> Map.add k (b::v) acc 
       | None -> Map.add k [b] acc 
      loop acc rest 
     | _    -> acc 
    loop Map.empty x |> Map.toList 

或者使用Option.toList你可以寫:

let toRel x = 
    let rec loop acc xs = 
     match xs with 
     | (k, b) :: rest -> 
      let acc = 
       let lst = Map.tryFind k acc |> Option.toList |> List.concat 
       Map.add k (b::lst) acc 
      loop acc rest 
     | _    -> acc 
    loop Map.empty x |> Map.toList 
+0

這是一個非常優雅的解決方案。你有沒有更高級功能的建議? – Khaine775

+1

我剛剛添加了一個比賽的例子,我認爲這是你想要做的。但是你也可以使用迭代器。 – Gustavo

相關問題