2009-11-27 8 views
13

Angenommen habe ich eine Liste von Tupel wie diese:Gruppe von mit Tupeln in F #

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

Und ich möchte eine Art von groupby zu tun, wie gehe ich das?

In Pseudo-Code-SQL sollte es in etwa so aussehen:

SELECT fst(tpl), sum(lst(tpl)) FROM [TupplesInList] GROUP BY fst(tpl) 

Nachgeben

[("A",22); ("B",1); ("C",3)] 

Ich könnte ein Wörterbuch machen und die Ints hinzufügen, wenn der Schlüssel vorhanden sind, aber ich kann kaum glauben, dass wäre die beste Lösung in einer so ausdrucksstarken Sprache wie F #.

Antwort

24

Eine Lösung:

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)) 

Edit: ... oder ohne Verrohrung:

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) 
14

auf Johan Antwort zu erweitern, neige ich dazu, eine Menge dieser Art, was zu tun und so gemacht haben die folgende verallgemeinerte Funktion.

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)) 

das für Ihr Tupel Fall arbeitet wie unten

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 

gesehen, aber auch mit anderen seqences wie eine Liste von Strings arbeiten

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