sailorcoding
sailorcoding

Reputation: 49

Summing the quantities in a list of tuples

For example, if I have a list like this:

[("pizza", 4); ("milkshake", 2); ("chocolate", 2); ("pizza", 3); ("milkshake", 3); ("pizza", 4)]

and I want to sum all the second elements of the tuples while the first tuple is the same. How should I do it?

The output should be:

[("pizza", 11); ("milkshake", 5); ("chocolate, 2")]

Upvotes: 0

Views: 174

Answers (1)

Mark Pattison
Mark Pattison

Reputation: 3029

You can used List.groupBy to group the items according to the item name:

let items = [("pizza", 4); ("milkshake", 2); ("chocolate", 2); ("pizza", 3); ("milkshake", 3); ("pizza", 4)]
let grouped = List.groupBy fst items

// returns the following:
// [("pizza", [("pizza", 4); ("pizza", 3); ("pizza", 4)]);
//  ("milkshake", [("milkshake", 2); ("milkshake", 3)]);
//  ("chocolate", [("chocolate", 2)])]

This returns a list of tuples where the first entry is the item name (e.g. pizza) and the second entry is itself a list, containing all the original tuples which match that name.

Then you can map each sub-list to the sum of the second entries:

let summed = List.map (fun (name, entries) -> (name, entries |> List.sumBy snd)) grouped

// returns [("pizza", 11); ("milkshake", 5); ("chocolate", 2)] as expected

The documentation for the List module shows all the built in functions for working with lists.

Note that fst and snd are built-in functions which return the first and second elements of a two-element tuple respectively.

Once you're more familiar with F#, you might want to use the forward pipe operator |> to do this more succinctly:

let summed =
    items
    |> List.groupBy fst
    |> List.map (fun (name, entries) -> (name, entries |> List.sumBy snd))

Upvotes: 3

Related Questions