F#中的SingleOrDefault

时间:2018-11-14 15:38:21

标签: linq f# c#-to-f#

类似于this问题-用F#编写LINQ的SingleOrDefault的最惯用的方法是什么?

3 个答案:

答案 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