Search code examples
linqf#seq

F# equivalent of LINQ Single


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?).


Solution

  • 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.