1

('a* 'b)配列をまとめたい

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

明らかにこれは理想的ではありません。+おそらく1つの方法は、とを定義しzerotuple組み込みのを使用することだと思います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

別の方法があります。これには、GenericZeroを使用する必要はありません。

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

編集:または、(ダニエルが提案したように)最大の互換性が必要Array.sumな場合は、空の配列のチェックを追加するだけです:

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 に答える
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 に答える