我想总结一个('a* 'b)
数组
let inline sumPair (array: ('a * 'b)[]) =
let array1, array2 = array |> Array.unzip
(Array.sum array1, array2 |> Array.sum)
显然这并不理想。我想也许一种方法是定义+
and zero
of my tuple
,并使用内置的Array.sum
,但找不到任何相关的教程。有什么帮助吗?
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)
它应该比第一个需要更少的分配。
如果您担心创建临时数组,这里有一个使用序列的简洁版本:
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
这是另一种方式。这不需要您使用 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),但如果您有一个巨大的数组,它确实具有可并行化的好处。