Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Summing multiple fields in Seq<'T>

Tags:

f#

seq

I am wanting to be able to sum multiple fields of a sequence. I don't know how to do this without iterating over the sequence multiple times. My perception is that this is inefficient. Is there a clever way to do this that I am not seeing?

type item = {
    Name : string
    DemandQty : decimal
    Weight : decimal
    UnitCost : decimal
}

let items =
    {1..10}
    |> Seq.map (fun x -> 
        {
            Name = string x
            DemandQty = decimal x
            Weight = decimal x
            UnitCost = decimal x
        })

// This Works for a single value
let costSum =
    items
    |> Seq.sumBy (fun x -> x.DemandQty * x.UnitCost)

// This is similar to what I would like to do
let costSum, weightSum =
    items
    |> Seq.sumBy (fun x -> x.DemandQty * x.UnitCost, x.DemandQty * x.Weight)

Ideally I can sum multiple values that I am calculating by mapping over the sequence. Is my thinking off here?

I would also be interested in knowing what the performance impact is going to be if I have to iterate through the sequence multiple times to calculate all of the sums I am wanting. My perception is that this would be inefficient.

like image 299
Matthew Crews Avatar asked Jan 05 '18 04:01

Matthew Crews


1 Answers

A straightforward way of summing is folding the sequence with a sum function:

let costSum, weightSum =
    items
    |> Seq.fold 
        (fun (costSum, weightSum) x -> (costSum + x.DemandQty * x.UnitCost, weightSum + x.DemandQty * x.Weight)) 
        (0m, 0m)

As for the performance impact of iterating over the sequence multiple time is that it depends. The work of iterating over the sequence is repeated. So at the face of it is less efficient. However for shorter sequences when the number of repeated iterations is constant the performance impact might be negligible. Also computational complexity theory states that constants are ignorable when the number of elements increases.

In short, if it matters, benchmark on expected inputs. If it doesn't have a large enough impact go with the solution that offers best clarity.

like image 110
Chris Jansson Avatar answered Sep 28 '22 07:09

Chris Jansson