F#equivalente de LINQ Single
seq (2)
Ok, entonces para la mayoría de las operaciones LINQ hay un equivalente de F #. (Generalmente en el módulo Seq, desde Seq = IEnumerable)
No puedo encontrar el equivalente de IEmumerable.Single
, prefiero Single
over First
(que es Seq.find), porque es más defensivo - afirma para mí que el estado es lo que espero.
Entonces veo un par de soluciones (además de usar Seq.find). (Estos podrían escribirse como métodos de extensión)
La firma de tipo para esta función, que estoy llamando solo, es
(''a->bool) -> seq<''a> -> ''a
let only = fun predicate src -> System.Linq.Enumerable.Single<''a>(src, predicate)
let only2 = Seq.filter >> Seq.exactlyOne
only2
es preferido, sin embargo no compilará (¿hay alguna pista sobre eso?).
Qué pasa
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
Muy unidiomático pero probablemente cercano al óptimo
EDITAR:
Solución con exactlyOne
let only2 f s= (Seq.filter f s) |> exactlyOne
En F # 2.0, esta es una solución que funciona sin enumerar toda la secuencia (cerca de su segundo enfoque):
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
Elijo devolver el tipo de option
ya que elevar la excepción es bastante inusual en las funciones de alto orden F #.
EDITAR:
En F # 3.0, como @Oxinabox se menciona en su comentario, Seq.exactlyOne existe en el módulo Seq.