Вопрос

Ok, so for most LINQ operations there is a F# equivalent. (Generally in the Seq module, since Seq= IEnumerable)

I can't find the equiv of IEmumerable.Single, I prefer Single over First (which is Seq.find), because it is more defensive - it asserts for me the state is what I expect.

So I see a couple of solutions (other than than using Seq.find). (These could be written as extension methods)

The type signature for this function, which I'm calling only, is

('a->bool) -> seq<'a> -> 'a

let only =  fun predicate src -> System.Linq.Enumerable.Single<'a>(src, predicate)

let only2 = Seq.filter >> Seq.exactlyOne

only2 is preferred, however it won't compile (any clues on that?).

Это было полезно?

Решение

In F# 2.0, this is a solution works without enumerating the whole sequence (close to your 2nd approach):

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

I choose to return option type since raising exception is quite unusual in F# high-order functions.

EDIT:

In F# 3.0, as @Oxinabox mentioned in his comment, Seq.exactlyOne exists in Seq module.

Другие советы

What about

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 

Very unidiomatic but probably close to optimal

EDIT:

Solution with exactlyOne

let only2 f s= (Seq.filter f s) |> exactlyOne
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top