我在Haskell中有一个函数,它从列表中找到取幂的最大值:
prob99 = maximum $ map (\xs -> (head xs)^(head (tail xs))) numbers
我需要找到的是结果列表中此最大值的位置。我该怎么做呢?
编辑:我找到了一个类似的解决方案:
n = [[519432,525806],[632382,518061]....
prob99b [a,b] = b* (log a)
answer = snd $ maximum (zip (map prob99b n) [1..])
答案 0 :(得分:34)
如何找到最大元素的索引?如何尝试所有索引并检查它们是否是最大值?
ghci> let maxIndex xs = head $ filter ((== maximum xs) . (xs !!)) [0..]
但这听起来像功能已经存在的东西。如果我使用现有的函数,我的代码将更具可读性,可维护性,甚至可能更高效。
所以我应该问问怎么做,在15分钟内我会得到一个答案和一些讽刺的评论。或者 - 我可以问Hoogle并立即得到有用的回应(如同建议的那样)
$ 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]
答案 1 :(得分:33)
import Data.List
elemIndex 'b' "abc" === Just 1
查找haskell函数的一个非常好的工具是Hoogle。允许您通过类型签名等搜索。
如果您想在一次传递中完成所有操作,我建议使用Data.List.mapAccumL,将迄今为止找到的最大数字的索引作为累加器传递。
答案 2 :(得分:7)
这可能不值得回答他自己,但我还不能发表评论。无论如何,这就是我写这个的方式:
import Data.List
import Data.Ord
maxIndex :: Ord a => [a] -> Int
maxIndex = fst . maximumBy (comparing snd) . zip [0..]
答案 3 :(得分:1)
如果您在Haskell中进行数值计算,您可能需要查看使其更容易和更有效的库。例如,hmatrix有一个有效maxIndex
的方法Vector
,其文档位于:https://hackage.haskell.org/package/hmatrix-0.17.0.1/docs/Numeric-LinearAlgebra-Data.html#g:14
> maxIndex $ vector [1, 3, 2]
1
当问题最初被问到时,方法的确切名称是不同的,但库也在那时。
答案 4 :(得分:1)
作为我的Haskeller新手,我会按照以下思路考虑:
zip [0..] xs
。 (请注意,Haskell索引从零开始,即列表的头是x !! 0
。)我想根据每个元组的第二个元素找到此压缩列表[(0, x!!0), (1, x!!1), ..., (n, x!!n)]
的最大值。根据我对Haskell的了解程度,有几种选择:
maximumBy (comparing snd)
将其写为Maxime wrote below。maximumBy
存在,但是我怀疑是这样,所以我可以根据要使用的类型签名在Hoogle上进行搜索:它返回一个类型的元素在两个a
参数(a
)上使用比较函数,从a
元素列表中选择通用类型a -> a -> Ordering
–要么是[a] -> (a -> a -> Ordering) -> a
,要么是参数的一些逻辑排列。考虑一下,将列表作为倒数第二个参数更有意义,因为这样一来,我们就会看到更好的循环,因此let's search for (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'
从左侧开始折叠(这意味着折叠功能中的累加器在左侧),并且仅当xj
大于xi
时,累积索引才会更新,因此这将返回第一个最大值的索引。如果有人对导入Data.List
怀恨在心,并且无法处理1000个项目长的列表,那么Prelude中的foldl1
就可以了。 Data.Vector
包使用类似的方法,只搜索“ maxIndex
” here和here。
Ord
,在这种情况下cmpBySnd
会变成
cmpBySnd (i, xi) (j, xj) = if xi < xj then j else i
在这一点上,人们可能会错过代数数据类型和高阶函数的好处(如果不知道,这几乎是不可能实现的,所以1)问的很好! 2)我可以将下一个读者指向诸如Learn You A Haskell For Great Good或Real World Haskell或this SO answer或this GitHub repo之类的资源。
(i, xi)
元组的第一个元素,最好使用内置函数fst :: (a, b) -> a
或自制函数first (a,b) = a
最终结果如下:
maxIndex :: Ord a => [a] -> Int
maxIndex = fst . maximumBy (comparing snd) . zip [0..]
-- or
-- maxIndex = fst . maxBySnd . zip [0..]