作为受歧视联盟的某个成员的列表元素的计数

时间:2012-06-02 20:17:51

标签: f# pattern-matching discriminated-union

我们说我有一个受歧视的联盟:

type foo = Bar | Baz | Batz

然后,我想检查列表中有多少类型为Baz的成员:

List.sumBy (function Bar -> 1 | _ -> 0) foos

是否有更惯用的方式来做到这一点?

5 个答案:

答案 0 :(得分:4)

请注意,您的示例不正确。它应该是:

List.sumBy (fun x -> match x with Baz -> 1 | _ -> 0) foos

可以改写为:

List.sumBy (function Baz -> 1 | _ -> 0) foos

我认为这里没有比在这里使用List.sumBy更加自律的方式。

答案 1 :(得分:3)

这取决于你如何定义“更惯用”。如果它是语言能力的同义词,除了其他因素之外,还有代码表现,那么同样简洁

List.fold (fun sum -> function Baz -> sum + 1 | _ -> sum) 0 foos

可能被认为更加惯用,因为它执行速度比F#2.0下List.sumBy的版本快3-4倍。

由于List.fold的实施针对列表进行了高度优化,而List.sumBy落后于Seq.sumBy,其中实施通过普通IEnumerable遍历,因此性能差异非常重要

答案 2 :(得分:0)

我会定义一个count函数。想要计算满足给定谓词的元素数量是一个非常常见的用例。

let count pred = List.sumBy (fun x -> if pred x then 1 else 0)

使用:

count (fun x -> x = Bar) foos

答案 3 :(得分:0)

这是我本能地做的。过滤|>长度似乎比求和或折叠更自然。没有检查性能。

let count = 
    myList 
        |> List.filter (fun elem -> match elem with | Baz -> true | _ -> false)
        |> List.length

答案 4 :(得分:0)

...为了完整性,不要忘记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