4

好的,所以对于大多数 LINQ 操作来说,都有一个 F# 等价物。(一般在 Seq 模块中,因为 Seq= IEnumerable)

我找不到 的等价物IEmumerable.Single,我更喜欢SingleFirst它是 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是首选,但它不会编译(有任何线索吗?)。

4

2 回答 2

3

关于什么

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
于 2012-03-24T10:19:51.070 回答
3

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

于 2012-03-24T10:32:11.677 回答