相当于LINQ Single的F#

时间:2012-03-24 09:56:54

标签: linq f# seq

好的,所以对于大多数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是首选,但它不会编译(任何线索?)。

2 个答案:

答案 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模块中。