F# 中的 SingleOrDefault
SingleOrDefault in F#
类似于 F# 中的 this question - what is the most idiomatic way to write LINQ's SingleOrDefault?
我的做法是 SequenceExtensions.fs
和
module Seq
let trySingle = function
| seq when seq |> Seq.isEmpty ->
None
| seq ->
seq
|> Seq.exactlyOne
|> Some
用于其他地方,如 [42] |> Seq.trySingle
。
如果您需要 SingleOrDefault
的确切行为,我建议如下:
module Seq
open System.Linq
let singleOrDefault (s : 'x seq) =
s.SingleOrDefault ()
否则,请查看您自己的答案以获得完全明智的解决方案。
如果您希望函数在序列为空时 return null
(或值类型的默认值),只需继续调用现有的 SingleOrDefault
方法即可。您可以很好地从 F# 调用 C# 方法。但是请记住,大多数 F# 本机类型不允许空值,因此这可能并不总是可行的。
如果你想让你的函数return一个选项类型,当序列包含零个或多个元素时回落到None
,你可以使用Seq.truncate
截断到前两个元素:
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
所做的。
另请注意,当序列包含多个元素时,此解决方案将 return 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
类似于 F# 中的 this question - what is the most idiomatic way to write LINQ's SingleOrDefault?
我的做法是 SequenceExtensions.fs
和
module Seq
let trySingle = function
| seq when seq |> Seq.isEmpty ->
None
| seq ->
seq
|> Seq.exactlyOne
|> Some
用于其他地方,如 [42] |> Seq.trySingle
。
如果您需要 SingleOrDefault
的确切行为,我建议如下:
module Seq
open System.Linq
let singleOrDefault (s : 'x seq) =
s.SingleOrDefault ()
否则,请查看您自己的答案以获得完全明智的解决方案。
如果您希望函数在序列为空时 return null
(或值类型的默认值),只需继续调用现有的 SingleOrDefault
方法即可。您可以很好地从 F# 调用 C# 方法。但是请记住,大多数 F# 本机类型不允许空值,因此这可能并不总是可行的。
如果你想让你的函数return一个选项类型,当序列包含零个或多个元素时回落到None
,你可以使用Seq.truncate
截断到前两个元素:
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
所做的。
另请注意,当序列包含多个元素时,此解决方案将 return 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