差別化された共用体があるとしましょう。
type foo = Bar | Baz | Batz
次に、リストのメンバーの数を確認したいと思いますBaz
。
List.sumBy (function Bar -> 1 | _ -> 0) foos
これを行うためのより慣用的な方法はありますか?
差別化された共用体があるとしましょう。
type foo = Bar | Baz | Batz
次に、リストのメンバーの数を確認したいと思いますBaz
。
List.sumBy (function Bar -> 1 | _ -> 0) foos
これを行うためのより慣用的な方法はありますか?
例が正しくないことに注意してください。そのはず:
List.sumBy (fun x -> match x with Baz -> 1 | _ -> 0) foos
これは次のように書き直すことができます。
List.sumBy (function Baz -> 1 | _ -> 0) foos
ここで使用するよりも理想的な方法はないと思いList.sumBy
ます。
「より慣用的な」をどのように定義するかによって異なります。それが、他の要因の中でもとりわけ、コードのパフォーマンスによって測定された言語能力の同義語である場合、同様に簡潔になります
List.fold (fun sum -> function Baz -> sum + 1 | _ -> sum) 0 foos
List.sumBy
F#2.0未満のバージョンよりも、実行速度が3〜4倍速いため、慣用的なものと見なされる場合があります。
List.fold
の実装はリスト用に特別に最適化されているため、パフォーマンスの格差は非常に大きくなりますが、実装が通常のトラバーサルを通過する場所List.sumBy
にフォールバックします。Seq.sumBy
IEnumerable
関数を定義しcount
ます。与えられた述語を満たす要素の数を数えたいというのは、かなり一般的なユースケースです。
let count pred = List.sumBy (fun x -> if pred x then 1 else 0)
使用する:
count (fun x -> x = Bar) foos
これは私が本能的にしたことです。フィルタ|>長さは合計や折りたたみよりも自然に見えます。パフォーマンスをチェックしていません。
let count =
myList
|> List.filter (fun elem -> match elem with | Baz -> true | _ -> false)
|> List.length
...完全を期すために、forループがパターンマッチできるというあまり知られていない事実を忘れないでください。ただし、パターンマッチングが不完全であるという警告が表示されますが、これは煩わしいことです。
open System
type foo = Bar | Baz of int | Batz of string * string
let myList = [Bar; Bar; Baz(1); Batz("x", "y"); Baz(2)]
let count =
let mutable acc = 0
for Baz(_) in myList do
acc <- acc + 1
acc