类似于this问题-用F#编写LINQ的SingleOrDefault的最惯用的方法是什么?
答案 0 :(得分:4)
如果您希望函数在序列为空时返回null
(或值类型的默认值),则继续并调用现有的SingleOrDefault
方法。您可以从F#调用C#方法。但是请记住,大多数F#本机类型都不接受空值,因此这并非总是可能的。
如果希望函数返回选项类型,并且当序列包含零个或多个元素时退回到None
,则可以使用Seq.truncate
截断到前两个元素:< / p>
let singleOrDefault s =
match s |> Seq.truncate 2 |> Seq.toList with
| [x] -> Some x
| _ -> None
或者类似地,对于也需要谓词的重载:
let singleOrDefaultP pred s =
match s |> Seq.filter pred |> Seq.truncate 2 |> Seq.toList with
| [x] -> Some x
| _ -> None
如果您希望同时使用这两个版本,则可以用另一个来表达,以使内容保持干燥,这很有意义:
let singleOrDefault s = singleOrDefaultP (fun _ -> true) s
与使用额外的Seq.isEmpty
检查相比,此解决方案的优势在于该序列仅被评估一次,并且仅在需要时评估。
偶然地,这正是the default implementation of SingleOrDefault
的作用。
还请注意,当序列包含多个元素时,此解决方案将返回None
,而不是像原始序列一样引发异常。这是处理F#错误的首选惯用方式。但是,如果您喜欢原始方式,则可以通过在匹配项中添加其他大小写来轻松实现:
let singleOrDefault s =
match s |> Seq.truncate 2 |> Seq.toList with
| [x] -> Some x
| [_;_] -> failWith "Too many" // replace with your favourite exception
| _ -> None
答案 1 :(得分:2)
如果您需要SingleOrDefault
的确切行为,建议采取以下措施:
module Seq
open System.Linq
let singleOrDefault (s : 'x seq) =
s.SingleOrDefault ()
否则,请参阅您自己的答案以寻求一个完全明智的解决方案。
答案 2 :(得分:1)
我的目的是与SequenceExtensions.fs
一起
module Seq
let trySingle = function
| seq when seq |> Seq.isEmpty ->
None
| seq ->
seq
|> Seq.exactlyOne
|> Some
要在其他地方使用,例如[42] |> Seq.trySingle
。