在F#中使用元组分组

Pet*_*ter 14 f#

假设我有一个像这样的tupples列表:

[("A",12); ("A",10); ("B",1);  ("C",2); ("C",1)]
Run Code Online (Sandbox Code Playgroud)

我想做一些groupby我如何处理它?

在伪代码SQL中它应该看起来像这样:

SELECT fst(tpl), sum(lst(tpl)) FROM [TupplesInList] GROUP BY fst(tpl)
Run Code Online (Sandbox Code Playgroud)

生产

 [("A",22); ("B",1); ("C",3)]
Run Code Online (Sandbox Code Playgroud)

如果密钥存在,我可以创建一个字典并添加整数,但我很难相信这将是F#表达的最佳解决方案.

Joh*_*bom 27

一个解决方案

let tuples = [("A",12); ("A",10); ("B",1);  ("C",2); ("C",1)]
tuples 
|> Seq.groupBy fst 
|> Seq.map (fun (key, values) -> (key, values |> Seq.sumBy snd))
Run Code Online (Sandbox Code Playgroud)

编辑: ...或没有管道:

let tuples = [("A",12); ("A",10); ("B",1);  ("C",2); ("C",1)]
Seq.map (fun (key, group) -> key, Seq.sumBy snd group)
        (Seq.groupBy fst tuples)
Run Code Online (Sandbox Code Playgroud)


Jos*_*hua 16

为了扩展Johan的答案,我倾向于做很多这样的事情,因此做了以下广义功能.

let group_fold key value fold acc seq =
    seq |> Seq.groupBy key 
        |> Seq.map (fun (key, seq) -> (key, seq |> Seq.map value |> Seq.fold fold acc))
Run Code Online (Sandbox Code Playgroud)

这适用于您的元组案例,如下所示

let tuples = [("A",12); ("A",10); ("B",1);  ("C",2); ("C",1)]

let regular = group_fold fst snd (+) 0 tuples 
let piped = tuples  |> group_fold fst snd (+) 0
Run Code Online (Sandbox Code Playgroud)

但也可以使用其他序列,如字符串列表

let strings = ["A12"; "A10"; "B1";  "C2"; "C1"]

let regular = group_fold (fun (x : string) -> x.[0]) (fun (x : string) -> int x.[1..]) (+) 0 strings 
let piped = strings  |> group_fold (fun x -> x.[0]) (fun x -> int x.[1..]) (+) 0
Run Code Online (Sandbox Code Playgroud)