如何在列表中查找函数最大值的值

Mik*_*nch 3 f#

我想找到的不仅是应用于列表的函数的最大值(我将使用List.maxBy),而且还要找到列表中出现的值.这感觉就像一个相当普遍的操作,并且考虑到F#库的丰富性,一般情况下我发现它实际上已经可用并不会感到惊讶,但如果是的话我似乎无法找到它!

为了举例说明,我希望能够映射列表domain和函数f

let domain = [0 .. 5]
let f x = -x * (x - 2)
Run Code Online (Sandbox Code Playgroud)

to (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
Run Code Online (Sandbox Code Playgroud)

在这一点上,我意识到这非常接近折叠操作,并放在一起

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
Run Code Online (Sandbox Code Playgroud)

代替.

我的问题是,这些惯用的F#解决这个问题的方法,或者确实有更好的解决方法吗?

Ste*_*sen 11

实际上,F#库提供了所有必要的高阶函数来简洁地表达:

domain
|> Seq.map (fun x -> x, f x)
|> Seq.maxBy snd
Run Code Online (Sandbox Code Playgroud)

注:更新为使用Seq.mapSeq.maxBy代替List.mapList.maxBy解决@ ildjarn的有关创建不必要的中间表关注.


ild*_*arn 5

斯蒂芬答案的另一种选择,即避免创建第二个List,同时执行f一个额外的时间:

domain
|> List.maxBy f
|> fun x -> x, f x
Run Code Online (Sandbox Code Playgroud)