F # sequence of running totals

Well, it looks like this should be easy, but I just don't get it. If I have a sequence of numbers, how do I create a new sequence made up of current totals? for example, for the sequence [1; 2; 3; 4], I want to match it with [1; 3; 6; 10]. Accordingly, in a functional way.

+6
functional-programming f #
source share
5 answers

Use List.scan :

 let runningTotal = List.scan (+) 0 >> List.tail [1; 2; 3; 4] |> runningTotal |> printfn "%A" 

Seq.scan implementation based on:

 let runningTotal seq' = (Seq.head seq', Seq.skip 1 seq') ||> Seq.scan (+) { 1..4 } |> runningTotal |> printfn "%A" 
+15
source share

Another variation using Seq.scan ( Seq.skip 1 gets rid of the initial zero):

 > {1..4} |> Seq.scan (+) 0 |> Seq.skip 1;; val it : seq<int> = seq [1; 3; 6; 10] 
+13
source share
 > Seq.scan (fun acc n -> acc + n) 0 [1;2;3;4];; val it : seq<int> = seq [0; 1; 3; 6; ...] 

With lists:

 > [1;2;3;4] |> List.scan (fun acc n -> acc + n) 0 |> List.tail;; val it : int list = [1; 3; 6; 10] 

Edit: Another way with sequences:

 let sum s = seq { let x = ref 0 for i in s do x := !x + i yield !x } 

Yes, there is a mutable variable, but I consider it more readable (if you want to get rid of the leading 0).

+5
source share

Not sure if this is the best way, but it should do the trick

  let input = [1; 2; 3; 4] let runningTotal = (input, 0) |> Seq.unfold (fun (list, total) -> match list with | [] -> None | h::t -> let total = total + h total, (t, total) |> Some) |> List.ofSeq 
0
source share

I thought it was worth talking about how to do this with record types, in case you are also looking for what you came here for.

Below is a fictional example demonstrating the concept of using treadmills around a track.

 type Split = double type Lap = { Num : int; Split : Split } type RunnerLap = { Lap : Lap; TotalTime : double } let lap1 = { Num = 1; Split = 1.23 } let lap2 = { Num = 2; Split = 1.13 } let lap3 = { Num = 3; Split = 1.03 } let laps = [lap1;lap2;lap3] let runnerLapsAccumulator = Seq.scan (fun rl l -> { rl with Lap = l; TotalTime = rl.TotalTime + l.Split }) // acumulator { Lap = { Num = 0; Split = 0.0 }; TotalTime = 0.0 } // initial state let runnerLaps = laps |> runnerLapsAccumulator printfn "%A" runnerLaps 
0
source share

All Articles