假设我有一个seq,如果有任何元素或None其他元素,我想返回最大的。F# 似乎没有这个内置。
这是我的尝试:
let tryMax xs =
if Seq.isEmpty xs
then
None
else
Seq.max xs |> Some
let tryMin xs =
if Seq.isEmpty xs
then
None
else
Seq.min xs |> Some
Run Code Online (Sandbox Code Playgroud)
我认为你的方法总体上是好的。有一个现在已删除的答案,建议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
Run Code Online (Sandbox Code Playgroud)
用法:
> 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
Run Code Online (Sandbox Code Playgroud)
一种可能更快的方法(我没有计时)是防止option在每个最小或最大计算结果上创建 ,同时防止第一项的多次迭代。
这也应该有更少的 GC 压力;)。
> 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
Run Code Online (Sandbox Code Playgroud)
用法:
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
Run Code Online (Sandbox Code Playgroud)
FWIW,这tryMinBy也是:
let tryMinBy projection (items : seq<_>) =
use e = items.GetEnumerator()
if e.MoveNext() then
let mutable minItem = e.Current
let mutable minValue = projection minItem
while e.MoveNext() do
let value = projection e.Current
if value < minValue then
minItem <- e.Current
minValue <- value
Some minItem
else
None
Run Code Online (Sandbox Code Playgroud)
全套:
let tryMinBy projection (items : seq<_>) =
use e = items.GetEnumerator()
if e.MoveNext() then
let mutable minItem = e.Current
let mutable minValue = projection minItem
while e.MoveNext() do
let value = projection e.Current
if value < minValue then
minItem <- e.Current
minValue <- value
Some minItem
else
None
Run Code Online (Sandbox Code Playgroud)