在 F# 中使用 array.fold 的累积和

cumulative sum using array.fold in F#

我有一个以下类型的数组

let myarray = [| 1 .. 5 |]

我想得到另一个数组,其中每个元素都是它之前的元素的累加和:

let mycumarray = [| 1 3 6.. 15 |]

我尝试做的是:

let sumArray array = Array.fold (fun acc elem -> acc + elem) 0.0 array
let mycumarray = sumArray myarray

然而它不起作用。有人对获得累计金额有什么建议吗?

我认为您正在寻找 Array.scan,这与 Array.fold 非常相似,但是 returns 所有状态值而不仅仅是最后一个:

(Array.scan (+) 0 myArray).[1..]

.[1..] 是数组切片器表示法 (see the MSDN on arrays in F#),用于删除第一个元素,这是必需的,因为 scan 在输出中包含初始状态。

Array.scan 无疑是最好的解决方案,但如果您愿意,可以使用 fold

let cumList xs = 
    List.ofSeq xs 
    |> List.fold (fun (acc, ys) elem -> 
                      let acc' = acc + elem 
                      in (acc', ys @ [acc'])) 
       (0, []) 
    |> snd 
    |> List.toArray

这是你的例子:

> cumList [|1..5|];;                                                                                                                               
val it : int [] = [|1; 3; 6; 10; 15|]

请注意,@ 不是最优的,但它很好地显示了已完成的工作(如果性能很重要,您可以使用 List.foldBack 或在其中执行 ::,最后 List.rev 以获得正确的顺序。

您也可以直接使用 Array.append 而不是 @

使示例在数字上通用:

let inline cumList xs = 
    List.ofSeq xs 
    |> List.fold (fun (acc, ys) elem -> 
                      let acc' = acc + elem 
                      in (acc', ys @ [acc'])) 
       (LanguagePrimitives.GenericZero, []) 
    |> snd 
    |> List.toArray

你看你只需要创建函数 inline 并使用 GenericZero 而不是 0 (假定为 int

顺便说一句:这也适用于 Array.scan 方法:

let inline cumList2 xs =
    Array.scan (+) LanguagePrimitives.GenericOne xs

备注 如果您只是从 1 而不是 0!

开始,则在这种情况下不需要数组切片