J'ai une fonction dans Haskell qui trouve la valeur maximale d'une exponentiation dans une liste:
prob99 = maximum $ map (\xs -> (head xs)^(head (tail xs))) numbers
Ce que je dois trouver, c'est l'emplacement de cette valeur maximale dans la liste résultante. Comment pourrais-je m'y prendre?
Edit: j'ai trouvé une solution qui va comme ceci:
n = [[519432,525806],[632382,518061]....
prob99b [a,b] = b* (log a)
answer = snd $ maximum (Zip (map prob99b n) [1..])
Comment trouver l'indice de l'élément maximum? Que diriez-vous d'essayer tous les index et de vérifier s'ils sont au maximum?
ghci> let maxIndex xs = head $ filter ((== maximum xs) . (xs !!)) [0..]
Mais cela ressemble à quelque chose pour lequel une fonction existe déjà. Mon code sera plus lisible, maintenable et probablement encore plus efficace si j'utilisais la fonction existante.
Pour info, vous pouvez également demander Hoogle qui peut rechercher par les signatures de type Haskell (comme Will l'a suggéré):
$ hoogle "Ord a => [a] -> Int" | head
<Nothing relevant>
$ # hmm, so no function to give me the index of maximum outright,
$ # but how about finding a specific element, and I give it the maximum?
$ hoogle "a -> [a] -> Int" | head
Data.List elemIndex :: Eq a => a -> [a] -> Maybe Int
Data.List elemIndices :: Eq a => a -> [a] -> [Int]
import Data.List
elemIndex 'b' "abc" === Just 1
Un très bon outil pour trouver des fonctions haskell est Hoogle . Vous permet entre autres de rechercher par signature de type.
Si vous vouliez tout faire en une seule fois, je recommanderais Data.List.mapAccumL, en passant l'index du plus grand nombre trouvé jusqu'à l'accumulateur.
Cela ne mérite probablement pas d'être dans sa propre réponse, mais je ne peux pas encore commenter. Quoi qu'il en soit, voici comment j'aurais écrit ceci:
import Data.List
import Data.Ord
maxIndex :: Ord a => [a] -> Int
maxIndex = fst . maximumBy (comparing snd) . Zip [0..]
Si vous effectuez un calcul numérique dans Haskell, vous voudrez peut-être examiner les bibliothèques qui le rendent plus facile et plus efficace. Par exemple hmatrix a une méthode maxIndex
pour efficace Vector
s, dont la documentation est ici: https://hackage.haskell.org/package /hmatrix-0.17.0.1/docs/Numeric-LinearAlgebra-Data.html#g:14
> maxIndex $ vector [1, 3, 2]
1
Les noms exacts des méthodes étaient différents lorsque la question a été posée à l'origine, mais la bibliothèque existait également à l'époque.
En tant que novice Haskeller que je suis, je penserais dans ce sens:
Zip [0..] xs
. (Notez que l'indexation Haskell commence à zéro, c'est-à-dire que la tête d'une liste est x !! 0
.)Je veux trouver le maximum de cette liste zippée [(0, x!!0), (1, x!!1), ..., (n, x!!n)]
en fonction du deuxième élément de chaque Tuple. Il existe quelques alternatives, basées sur ma connaissance de Haskell:
maximumBy (comparing snd)
, si je savais seulement que ces fonctions existent.maximumBy
existe mais je soupçonnais quelque chose comme ça, donc je pouvais le rechercher sur Hoogle en fonction de la signature de type que j'utiliserais: il retourne un élément de type type générique a
à partir d'une liste d'éléments a
, en utilisant une fonction de comparaison sur deux paramètres a
(a -> a -> Ordering
) - au total, ce serait [a] -> (a -> a -> Ordering) -> a
, ou une permutation plus logique des arguments. En y pensant, mettre la liste comme avant-dernier argument a plus de sens, car cela permet un meilleur curry comme nous le verrons dans un instant, alors recherchons(a -> a -> Ordering) -> [a] -> a
.import Data.List (foldl1')
maxBySnd :: Ord a => [(Int, a)] -> (Int, a)
maxBySnd = foldl1 cmpBySnd
where
cmpBySnd (i, xi) (j, xj) = case xi `compare` xj of
LT -> (j, xj)
_ -> (i, xi)
foldl1'
Commence à se plier à partir de la gauche (ce qui signifie que l'accumulateur est à gauche dans la fonction de pliage), et l'index accumulé est mis à jour uniquement si xj
est supérieur à xi
, donc cela renverra l'index du premier maximum. Si quelqu'un a une rancune contre l'importation de Data.List
Et ne fonctionne pas avec des listes de 1000 éléments, alors foldl1
De Prelude fera l'affaire. Le package Data.Vector
Utilise une approche similaire, il suffit de rechercher "maxIndex
" ici et ici .
Ord
pour des objets comparables, auquel cas cmpBySnd
deviendrait cmpBySnd (i, xi) (j, xj) = if xi < xj then j else i
À ce stade, on manquerait les avantages des types de données algébriques et des fonctions d'ordre supérieur (ce qui est presque impossible à réaliser si l'on ne sait pas), donc 1) c'est bien que vous posiez la question! 2) puis-je diriger le lecteur suivant vers une ressource comme Learn You A Haskell For Great Good , or Real World Haskell , or this SO answer , ou ce dépôt GitHub .
(i, xi)
Résultant, de préférence avec la fonction intégrée fst :: (a, b) -> a
, ou avec la fonction maison first (a,b) = a
Le résultat final est le suivant:
import Data.List (maximumBy)
import Data.Ord (comparing)
maxIndex :: Ord a => [a] -> Int
maxIndex = fst . maximumBy (comparing snd) . Zip [0..]
-- or
-- maxIndex = fst . maxBySnd . Zip [0..]