Думаю, ваш подход в целом хорош. Был удален ответ, в котором предлагалось использовать try/with
для предотвращения двойной оценки первого элемента путем выявления ошибки для пустых последовательностей, но это тоже может быть дорогостоящим.
Если вы хотите предотвратить двойная оценка, вы можете использовать Seq.cache
или вообще не использовать Seq
(вместо этого используйте List
или Array
). Или используйте fold, которая повторяется только один раз:
module Seq =
let tryMin sq =
sq
|> Seq.fold(fun x y ->
match x with None -> Some y | Some x -> Some(min x y)) None
Использование:
> Seq.tryMin Seq.empty<int>;;
val it : int option = None
> Seq.tryMin (Seq.singleton 2L);;
val it : int64 option = Some 2L
> Seq.tryMin (seq { 2; 3});;
val it : int option = Some 2
> Seq.tryMin (seq { 2; -3});;
val it : int option = Some -3
Потенциально более быстрый метод (я не учел его) - предотвратить создание option
для каждого результата вычисления минимума или максимума, и в то же время предотвращение многократных итераций первого элемента.
Этот должен иметь гораздо меньшее давление G C;).
module Seq =
let tryMin (sq: seq<_>) =
use e = sq.GetEnumerator()
// this returns false if there is no first item
if e.MoveNext() then
let mutable result = e.Current
while e.MoveNext() do
result <- min e.Current result
Some result
else
None
Использование:
> Seq.tryMin Seq.empty<int>;;
val it : int option = None
> Seq.tryMin (Seq.singleton 2L);;
val it : int64 option = Some 2L
> Seq.tryMin (seq { 2; 3});;
val it : int option = Some 2
> Seq.tryMin (seq { 2; -3});;
val it : int option = Some -3