我想找到的不仅是应用于列表的函数的最大值(我将使用List.maxBy),而且还要找到列表中的值。这感觉就像是一个相当普遍的操作,并且考虑到F#库的丰富性,一般来说我发现它实际上已经可用并不会感到惊讶,但如果是的话我似乎无法找到它!
为了举例说明,我希望能够映射列表domain
和函数f
let domain = [0 .. 5]
let f x = -x * (x - 2)
到(1, 1)
(因为应用于列表中其他元素的函数小于1)。
我首先尝试过这个:
let findMaximum domain f =
let candidates = [ for x in domain do
yield x, f x ]
let rec findMaximumHelper domain f currentMax =
match domain with
| [] -> currentMax
| head::tail ->
let cand = f head
match currentMax with
| None ->
let newMax = Some(head, cand)
findMaximumHelper tail f newMax
| Some(maxAt, possMax) ->
let newMax =
if cand > possMax then Some(head, cand)
else Some(maxAt, possMax)
findMaximumHelper tail f newMax
findMaximumHelper domain f None
let answer = findMaximum domain f
此时我意识到这非常接近 fold 操作,并且放在一起
let findMaximum2 domain f =
let findMaximumHelper f acc x =
let cand = f x
match acc with
| None -> Some(x, cand)
| Some(maxAt, possMax) ->
if cand > possMax then Some(x, cand)
else Some(maxAt, possMax)
List.fold (findMaximumHelper f) None domain
let answer2 = findMaximum2 domain f
代替。
我的问题是,这些惯用的F#解决这个问题的方法,或者确实有更好的解决方法吗?
答案 0 :(得分:11)
实际上,F#库提供了所有必要的高阶函数来简洁地表达:
domain
|> Seq.map (fun x -> x, f x)
|> Seq.maxBy snd
注意:已更新为使用Seq.map
和Seq.maxBy
而不是List.map
和List.maxBy
来解决@ildjarn对创建不必要的中间列表的担忧。
答案 1 :(得分:5)
斯蒂芬答案的另一种选择,即避免创建第二个List
,同时执行f
一次额外的时间:
domain
|> List.maxBy f
|> fun x -> x, f x