2011-04-22 54 views
3

我想查找应用于列表的函数的最大值(为此我只使用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 

此时我才发现这是非常接近操作,并放在一起

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#方式解决这个问题,或者确实有更好的解决方法吗?

+1

这个问题是没有意义的我。 'List.maxBy' * already *返回列表中的值,而不是投影函数的返回值。或者说这只是一个说你想要两个而已? – ildjarn 2011-04-22 21:07:01

+0

感谢@ildjarn,你说得很对 - 我没有那么多(x,f x)作为值x。我的错误是这些值恰好吻合的例子的糟糕选择,再加上看到一个错误的在线例子,这让我相信List.maxBy在函数应用后返回了最大值(例如,list |> List。 map f |> List.max)。 [MSDN文档](http://msdn.microsoft.com/en-us/library/ee340331.aspx)在主题上非常清晰,所以我没有真正找到任何借口! – 2011-04-22 21:49:36

+0

啊,不用担心。它只是让你的问题混淆,因为内建函数已经做了你所要求的:-P – ildjarn 2011-04-22 22:03:50

回答

11

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

domain 
|> Seq.map (fun x -> x, f x) 
|> Seq.maxBy snd 

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

5

的替代斯蒂芬的回答,即避免造成第二List,与执行f一个额外的时间的权衡:

domain 
|> List.maxBy f 
|> fun x -> x, f x 
相关问题