【问题标题】:Finding index of element in a list in Haskell?在 Haskell 的列表中查找元素的索引?
【发布时间】:2010-12-02 14:10:06
【问题描述】:

我在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..])

【问题讨论】:

    标签: list haskell indexing


    【解决方案1】:
    import Data.List
    elemIndex 'b' "abc" === Just 1
    

    查找haskell 函数的一个非常好的工具是Hoogle。允许您按类型签名等进行搜索。

    如果您想一次性完成所有操作,我建议您使用 Data.List.mapAccumL,将迄今为止找到的最大数字的索引作为累加器传递。

    【讨论】:

    • 你能告诉如何将elemIndex的输出转换为Int(不是Maybe Int吗?
    【解决方案2】:

    如何找到最大元素的索引?尝试所有索引并检查它们是否为最大值怎么样?

    ghci> let maxIndex xs = head $ filter ((== maximum xs) . (xs !!)) [0..]
    

    但这听起来像是已经存在函数的东西。如果我使用现有的函数,我的代码将更具可读性、可维护性,甚至可能更高效。

    仅供参考,你也可以问可以搜索的Hoogle 通过 Haskell 类型签名(如 Will 建议的那样):

    $ 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]
    

    【讨论】:

    • 好吧,看来除了我之外的每个人都生来就很棒,不是吗。但实际上,我什至不知道 Hoogle 的存在,而且我还在学习 Haskell。下次我会知道的。
    • @Jonno_FTW:我为自己的刻薄/愤世嫉俗道歉。不是每个人都生来就很棒,有些人不是天生的。你也可以变得很棒。 Pythonesque 编程中的一个好规则是:如果我发现我正在编写相同的东西 3 次,也许我应该为它创建一个函数。在 Haskellesque 编程中,常数是 e 而不是 3。同样的规则也适用于元编程。如果您发现需要大量查找有用的函数,最好尝试找出是否有更好的方法来执行此函数搜索过程,然后再发现 Hoogle。 mtfbwu
    • @Jonno_FTW 除非您准备好依赖它,否则不要开始使用 Hoogle。作为一个更有经验的 Haskell 程序员,我一确定我正在尝试做的事情所涉及的类型,就会转向 Hoogle。当我在例如编程时,这是一个问题。 Python,当我因为没有 Poogle 而感到沮丧时。 :(
    【解决方案3】:

    这可能不应该出现在他自己的答案中,但我还不能发表评论。不管怎样,我会这样写:

    import Data.List
    import Data.Ord
    
    maxIndex ::  Ord a => [a] -> Int
    maxIndex = fst . maximumBy (comparing snd) . zip [0..]
    

    【讨论】:

      【解决方案4】:

      如果您在 Haskell 中进行数值计算,您可能需要研究使其更容易和更高效的库。例如hmatrix 有一个方法maxIndex 用于高效的Vectors,其文档在这里:https://hackage.haskell.org/package/hmatrix-0.17.0.1/docs/Numeric-LinearAlgebra-Data.html#g:14

      > maxIndex $ vector [1, 3, 2]
      1
      

      最初提出问题时,方法的确切名称不同,但那时库也存在。

      【讨论】:

        【解决方案5】:

        作为一个 Haskeller 新手,我会按照以下思路思考:

        1. Haskell 列表是链表,因此我们需要手动将索引附加到元素:zip [0..] xs。 (请注意,Haskell 索引从零开始,即列表的头部是x !! 0。)
        2. 我想根据每个元组的第二个元素找到这个压缩列表[(0, x!!0), (1, x!!1), ..., (n, x!!n)]的最大值。根据我对 Haskell 的了解程度,有几种选择:

          • 如果我只知道这些函数存在,我可以将其写为 Maxime wrote below,使用 maximumBy (comparing snd)
          • 我不知道maximumBy 存在,但我怀疑是这样的,所以我可以根据我将使用的类型签名在Hoogle 上搜索它:它返回一个泛型类型@987654335 的元素@ 来自a 元素列表,在两个a 参数(a -&gt; a -&gt; Ordering)上使用比较函数——总共可以是[a] -&gt; (a -&gt; a -&gt; Ordering) -&gt; a,或者是参数的一些更合乎逻辑的排列。想一想,将列表作为倒数第二个参数更有意义,因为这样可以更好地进行柯里化,我们稍后会看到,所以let's search for(a -&gt; a -&gt; Ordering) -&gt; [a] -&gt; 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 包使用类似的方法,只需搜索“maxIndexherehere

          • 我什至不知道可比较对象的类型类 Ord,在这种情况下 cmpBySnd 会变成

              cmpBySnd (i, xi) (j, xj) = if xi < xj then j else i
          

          在这一点上,人们会错过代数数据类型和高阶函数的好处(如果人们不知道这一事实几乎是不可能实现的),所以 1) 你问得很好! 2) 我可以将下一位读者指向Learn You A Haskell For Great GoodReal World Haskellthis SO answerthis GitHub repo 之类的资源。

        3. 我们仍然需要获取结果(i, xi)元组的第一个元素,最好使用内置函数fst :: (a, b) -&gt; a,或者使用自制函数first (a,b) = a

        最终结果如下:

        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..]
        

        【讨论】:

          猜你喜欢
          • 2013-01-11
          • 2013-04-17
          • 2015-02-07
          • 2013-07-26
          • 2021-06-25
          • 2014-09-03
          • 2013-01-17
          • 2016-03-22
          • 2019-12-31
          相关资源
          最近更新 更多