2009-11-27 5 views
13

Supongamos que tengo una lista de tupples como estos:Grupo a funcionar con tuplas de F #

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

Y me gustaría hacer algún tipo de groupby ¿Cómo puedo manejar eso?

En pseudocódigo-SQL debe ser algo como esto:

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

rendimiento

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

que podría hacer un diccionario y añadir los enteros si existe la clave, pero apenas puede creer que sería la mejor solución en un lenguaje tan expresivo como F #.

Respuesta

24

Una solución:

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

Editar: ... o sin tuberías:

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

Para ampliar la respuesta de Johan, que tienden a hacer esta cosa especie mucho y por lo que han hecho la siguiente función generalizada.

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

que funciona para su caso tupla como se ve a continuación

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 

sino también trabajará con otras seqences como una lista de cadenas

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