SingleOrDefault в F # - PullRequest
       18

SingleOrDefault в F #

0 голосов
/ 14 ноября 2018

Подобно этому вопросу - какой самый идиоматичный способ написания LINQ SingleOrDefault на F #?

Ответы [ 3 ]

0 голосов
/ 14 ноября 2018

Если вам нужно точное поведение SingleOrDefault, я предлагаю следующее:

module Seq

open System.Linq

let singleOrDefault (s : 'x seq) =
    s.SingleOrDefault ()

В противном случае см. Свой собственный ответ для совершенно разумного решения.

0 голосов
/ 14 ноября 2018

Если вы хотите, чтобы функция возвращала null (или значение по умолчанию для типов значений), когда последовательность пуста, просто вызовите существующий метод SingleOrDefault.Вы можете вызывать методы C # из F # просто отлично.Имейте в виду, однако, что большинство собственных типов F # не допускают нулевых значений, поэтому это не всегда возможно.

Если вы хотите, чтобы ваша функция возвращала тип параметра, возвращаясь к 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 заключается в том, чтопоследовательность оценивается только один раз и только так, как нужно.

Кстати, это именно то, что делает реализация по умолчанию 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
0 голосов
/ 14 ноября 2018

Мой вариант - иметь SequenceExtensions.fs с

module Seq 

let trySingle = function
    | seq when seq |> Seq.isEmpty ->
        None
    | seq ->
        seq
        |> Seq.exactlyOne
        |> Some

, который будет использоваться в другом месте, например [42] |> Seq.trySingle.

...