好的,所以对于大多数LINQ操作都有一个F#等价物。 (通常在Seq模块中,因为Seq = IEnumerable)
我找不到IEmumerable.Single
的等价物,我更喜欢Single
而不是First
(这是Seq.find),因为它更具防御性 - 它为我声明状态是我所期待的。
所以我看到了几个解决方案(除了使用Seq.find之外)。 (这些可以写为扩展方法)
此函数的类型签名(我只调用它)是
('a->bool) -> seq<'a> -> 'a
let only = fun predicate src -> System.Linq.Enumerable.Single<'a>(src, predicate)
let only2 = Seq.filter >> Seq.exactlyOne
only2
是首选,但它不会编译(任何线索?)。
答案 0 :(得分:2)
怎么样?
let Single source f =
let worked = ref false
let newf = fun a ->
match f a with
|true ->
if !worked = true then failwith "not single"
worked := true
Some(a)
|false -> None
let r = source |> Seq.choose newf
Seq.nth 0 r
非常单一但可能接近最佳
exactlyOne
let only2 f s= (Seq.filter f s) |> exactlyOne
答案 1 :(得分:2)
在F#2.0中,这是一个解决方案,无需枚举整个序列(接近第二种方法):
module Seq =
let exactlyOne seq =
match seq |> Seq.truncate 2 with
| s when Seq.length s = 1 -> s |> Seq.head |> Some
| _ -> None
let single predicate =
Seq.filter predicate >> exactlyOne
我选择返回option
类型,因为在F#高阶函数中引发异常是非常不寻常的。
修改强>
在F#3.0中,正如@Oxinabox在评论中提到的那样,Seq.exactlyOne存在于Seq模块中。