1

我想总结一个('a* 'b)数组

let inline sumPair (array: ('a * 'b)[]) =
    let array1, array2 = array |> Array.unzip
    (Array.sum array1, array2 |> Array.sum)

显然这并不理想。我想也许一种方法是定义+and zeroof my tuple,并使用内置的Array.sum,但找不到任何相关的教程。有什么帮助吗?

4

3 回答 3

4
let inline sumPair source = 
  let inline zero() = LanguagePrimitives.GenericZero
  Seq.fold (fun (xAcc, yAcc) (x, y) -> (xAcc + x, yAcc + y)) (zero(), zero()) source

正如您在评论中所说的那样,它应该尽可能高效,我认为没有任何东西可以击败命令式版本:

let inline sumPair source = 
  let mutable xAcc = LanguagePrimitives.GenericZero
  let mutable yAcc = LanguagePrimitives.GenericZero
  for x, y in source do
    xAcc <- xAcc + x
    yAcc <- yAcc + y
  (xAcc, yAcc)

它应该比第一个需要更少的分配。

于 2012-10-03T19:46:33.983 回答
1

如果您担心创建临时数组,这里有一个使用序列的简洁版本:

let inline sumPair (array: _ []) =
    Seq.sumBy fst array, Seq.sumBy snd array

一个稍长但可能更有效的变体是:

let inline sumPair (array: _ []) =
        array |> Seq.map fst |> Seq.sum, array |> Seq.map snd |> Seq.sum
于 2012-10-03T19:43:36.560 回答
1

这是另一种方式。这不需要您使用 GenericZero:

let inline sumPair (array : (^T * ^U)[]) =
    array
    |> Array.reduce (fun (x0, y0) (x1, y1) ->
        (x0 + x1), (y0 + y1))

编辑:或者,如果您想要最大程度地兼容Array.sum(如 Daniel 建议的那样),只需添加一个空数组检查:

let inline sumPair (array : (^T * ^U)[]) =
    if Array.isEmpty array then
        LanguagePrimitives.GenericZero, LanguagePrimitives.GenericZero
    else
        array
        |> Array.reduce (fun (x0, y0) (x1, y1) ->
            (x0 + x1), (y0 + y1))

此代码不会完全内联(IL 仍将调用 Array.reduce),但如果您有一个巨大的数组,它确实具有可并行化的好处。

于 2012-10-04T00:11:43.140 回答