I want to extract a single item from a sequence in F#, or give an error if there is none or more than one. What is the best way to do this?
I currently have
let element = data |> (Seq.filter (function | RawXml.Property (x) -> false | _ -> true))
|> List.of_seq
|> (function head :: [] -> head | head :: tail -> failwith("Too many elements.") | [] -> failwith("Empty sequence"))
|> (fun x -> match x with MyElement (data) -> x | _ -> failwith("Bad element."))
It seems to work, but is it really the best way?
Edit: As I was pointed in the right direction, I came up with the following:
let element = data |> (Seq.filter (function | RawXml.Property (x) -> false | _ -> true))
|> (fun s -> if Seq.length s <> 1 then failwith("The sequence must have exactly one item") else s)
|> Seq.hd
|> (fun x -> match x with MyElement (_) -> x | _ -> failwith("Bad element."))
I guess it’s a little nicer.
Sequence has a find function.
but if you want to ensure that the seq has only one element, then doing a Seq.filter, then take the length after filter and ensure it equals one, and then take the head. All in Seq, no need to convert to a list.
Edit:
On a side note, I was going to suggest checking that the tail of a result is empty (O(1), instead of using the function
length(O(n)). Tail isn’t a part of seq, but I think you can work out a good way to emulate that functionality.