1

Let's say I have a discriminated union:

type foo = Bar | Baz | Batz

Then, I want to check how many members of a list are of type Baz:

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

Is there a more idiomatic way to do this?

4

5 回答 5

4

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

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

可以重写为:

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

我认为没有比List.sumBy在这里使用更惯用的方式了。

于 2012-06-02T20:31:43.683 回答
3

这取决于您如何定义“更惯用”。如果它是通过代码性能等因素衡量的语言熟练程度的同义词,那么同样简洁

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遍历的地方。

于 2012-06-03T03:18:26.063 回答
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
于 2012-06-03T20:22:44.400 回答
0

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

let count = 
    myList 
        |> List.filter (fun elem -> match elem with | Baz -> true | _ -> false)
        |> List.length
于 2012-06-03T20:14:13.440 回答
0

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

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

利用:

count (fun x -> x = Bar) foos
于 2012-06-03T19:41:48.633 回答