为什么 Array2D 没有折叠操作?

Why does Array2D not have a fold operation?

我刚刚遇到一个情况,在 Array2D 上使用 fold/foldi 方法会很有用,我想知道,如果有原因,为什么 Array2D 没有它们。

由于我的 array2d 非常大,我不想先将其转换为其他格式。

这只是一个罕见的用例还是有技术原因,为什么没有添加这些方法?或者有没有一种方法可以在不触及数组中的数据的情况下实现相同的效果(如移动它)?

我不认为 Array2D 没有在标准中附带这些功能有什么特别的原因,因为它确实有 map/mapi。无论如何,使用锯齿状数组可能会更好地满足您想要处理多维数组的用例,因此添加它们的动力很小。

您没有理由不能自己定义它们。

这里有一个折叠的例子:

let foldi (folder: int -> int -> 'S -> 'T -> 'S) (state: 'S) (array: 'T[,]) =
    seq {
        for x in 0 .. Array2D.length1 array - 1 do
            for y in 0 .. Array2D.length2 array - 1 do
                yield (x, y, array.[x, y])
    }
    |> Seq.fold (fun acc (x, y, e) -> folder x y acc e) state

要了解常规折叠和更深入的解释它是如何工作的,您可以查看 here

我认为在标准 Array2D 模块中包含此功能会非常有用。您可以为 the Visual F# repository 打开一个问题并帮助我们添加它 :-).

除了@scrwtp 写的,你还可以使用更直接的可变实现。对于像这样的基本功能,我认为使用变异是可以的,而且会快一点:

let foldi (folder: int -> int -> 'S -> 'T -> 'S) (state: 'S) (array: 'T[,]) =
    let mutable state = state
    for x in 0 .. Array2D.length1 array - 1 do
        for y in 0 .. Array2D.length2 array - 1 do
            state <- folder x y state (array.[x, y])
    state

如果我需要使用折叠功能,我通常使用Seq.cast,但这仅适用于折叠(不适用于foldi)。

我正在添加这个解决方案,如果有人需要,例如,扫描:

let array2dFold folder (state:'State) (source:'T[,]) =
      source
      |>   ( Seq.cast<'T> >> Seq.fold folder state ) 

由于它不依赖于突变,因此它很可能比以前的解决方案慢。