2011-03-29 32 views
5

好吧,这看起来应该很容易,但我只是没有得到它。如果我有一系列数字,我如何生成一个由运行总数组成的新序列?例如对于序列[1; 2; 3; 4],我想将它映射到[1; 3; 6; 10]。以适当的功能方式。f#运行总数

回答

14

使用List.scan

let runningTotal = List.scan (+) 0 >> List.tail 

[1; 2; 3; 4] 
|> runningTotal 
|> printfn "%A" 

Seq.scan基于实现:

let runningTotal seq' = (Seq.head seq', Seq.skip 1 seq') ||> Seq.scan (+) 

{ 1..4 } 
|> runningTotal 
|> printfn "%A" 
+0

这是非常酷的,但我希望做一个序列而不是一个列表。 – Aidan 2011-03-29 21:33:10

+0

@Aidan:编辑添加适当的Seq.scan实现。 – ildjarn 2011-03-29 21:37:35

+0

很酷,就是那个。谢谢。 – Aidan 2011-03-29 21:47:37

5
> Seq.scan (fun acc n -> acc + n) 0 [1;2;3;4];; 
val it : seq<int> = seq [0; 1; 3; 6; ...] 

随着名单:

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

编辑:另一种方式与序列:

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

是的,有一个可变的变量,但我觉得它更具可读性(如果你想获得摆脱领先的0)。

+0

很酷,谢谢。然而,它似乎产生了一个更大的序列,初始值为0,它是否不像真实的地图。 – Aidan 2011-03-29 21:27:41

0

不知道这是最好的方式,但它应该使用Seq.scan做的伎俩

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 
13

另一个变化(Seq.skip 1摆脱领先零):

> {1..4} |> Seq.scan (+) 0 |> Seq.skip 1;; 
val it : seq<int> = seq [1; 3; 6; 10] 
+0

+1最简单的答案呢。 – Daniel 2011-03-29 21:49:18

+2

感谢Daniel,F#为我的病态提供了简洁,优雅的解决方案。 – 2011-03-29 21:54:33

+1

我也是。我担心程序员的命运与F#交织在一起。 – Daniel 2011-03-29 21:58:44