2011-04-22 5 views
3

Je veux trouver non seulement la valeur maximale d'une fonction appliquée à une liste (pour laquelle je voudrais simplement utiliser List.maxBy), mais aussi la valeur dans la liste cela s'est produit à. Cela ressemble à une opération assez commune et compte tenu de la richesse des bibliothèques F # en général je ne serais pas du tout surpris de découvrir que c'était déjà disponible mais je n'arrive pas à le trouver si c'est le cas!Comment trouver la valeur dans une liste où une valeur maximale d'une fonction se produit

Pour illustrer par un exemple, je veux être en mesure de cartographier une liste domain et une fonction f

let domain = [0 .. 5] 
let f x = -x * (x - 2) 

à (1, 1) (puisque la fonction appliquée à un autre élément de la liste est inférieure à 1) .

J'ai d'abord essayé ceci:

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 

à quel point je me suis rendu ce qui est très proche d'une opération fois et mis ensemble

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 

à la place. Ma question est la suivante: ces moyens idiomatiques sont-ils pour résoudre ce problème, ou y a-t-il une meilleure façon de le résoudre?

+1

Cette question n'a pas de sens pour moi. 'List.maxBy' * déjà * renvoie la valeur dans la liste, pas la valeur de retour de la fonction de projection. Ou était-ce simplement un phrasé étrange pour dire que vous voulez les deux? – ildjarn

+0

Merci @ildjarn, vous avez raison - je n'étais pas tellement après la paire (x, f x) que la valeur x. Mon erreur ici était le mauvais choix d'un exemple où ces valeurs coïncident, en plus de voir un mauvais exemple en ligne qui m'a amené à croire que List.maxBy renvoyait la valeur maximale après que la fonction ait été appliquée (ie fait list> Liste. carte f |> List.max). La [documentation MSDN] (http://msdn.microsoft.com/fr-fr/library/ee340331.aspx) est assez claire sur le sujet, donc je n'ai pas vraiment d'excuses! –

+0

Ah, pas de soucis. Cela a rendu votre question déroutante puisque la fonctionnalité intégrée faisait déjà ce que vous demandiez :-P – ildjarn

Répondre

11

En effet, la bibliothèque F # fournit toutes les fonctions d'ordre supérieur nécessaires pour exprimer succinctement:

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

Note: mis à jour pour utiliser Seq.map et Seq.maxBy au lieu de List.map et List.maxBy pour répondre @ préoccupations de ildjarn sur la création une liste intermédiaire inutile.

5

Une alternative à la réponse de Stephen, qui évite la création d'un deuxième List, avec le compromis entre l'exécution de f un temps supplémentaire:

domain 
|> List.maxBy f 
|> fun x -> x, f x 
Questions connexes