Ok, this looks like it should be easy, but I'm just not getting it. If I have a sequence of numbers, how do I generate a new sequence made up of the running totals? eg for a sequence [1;2;3;4], I want to map it to [1;3;6;10]. In a suitably functional way.
Asked
Active
Viewed 2,358 times
5 Answers
16
Use List.scan
:
let runningTotal = List.scan (+) 0 >> List.tail
[1; 2; 3; 4]
|> runningTotal
|> printfn "%A"
Seq.scan
-based implementation:
let runningTotal seq' = (Seq.head seq', Seq.skip 1 seq') ||> Seq.scan (+)
{ 1..4 }
|> runningTotal
|> printfn "%A"

ildjarn
- 62,044
- 9
- 127
- 211
-
This is very cool, however I was hoping to do this for a Sequence rather than a list. – Aidan Mar 29 '11 at 21:33
-
@Aidan : Edited to add proper Seq.scan implementation. – ildjarn Mar 29 '11 at 21:37
-
Cool, that's the one. Thank you. – Aidan Mar 29 '11 at 21:47
14
Another variation using Seq.scan
(Seq.skip 1
gets rid of the leading zero):
> {1..4} |> Seq.scan (+) 0 |> Seq.skip 1;;
val it : seq<int> = seq [1; 3; 6; 10]

Stephen Swensen
- 22,107
- 9
- 81
- 136
-
2Thanks Daniel, F# feeds my sickness for succinct, elegant solutions. – Stephen Swensen Mar 29 '11 at 21:54
-
1
5
> 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's a mutable variable, but I find it more readable (if you want to get rid of the leading 0).

Laurent
- 2,951
- 16
- 19
-
cool, thank you. However it seems to generate a larger sequence, with an initial 0, do it doesn't feel like a true map. – Aidan Mar 29 '11 at 21:27
1
Figured it was worthwhile to share how to do this with Record Types in case that's also what you came here looking for.
Below is a fictitious example demonstrating the concept using runner laps 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

pim
- 12,019
- 6
- 66
- 69
0
Not sure 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

JaredPar
- 733,204
- 149
- 1,241
- 1,454