【问题标题】:Finding maximum element in a list of tuples在元组列表中查找最大元素
【发布时间】:2016-09-15 01:21:52
【问题描述】:

我是 Haskell 的初学者。我有一个我在 Haskell 中使用的元组列表:结构是这样的 [(a,b),(c,d),(e,f),(g,h)]

我想要的是根据第二个值返回这个元组中的最大元素: 所以如果元组列表是[(4,8),(9,10),(15,16),(10,4)],我希望最大元素是(15,16)。

但我不知道该怎么做。这是我目前的尝试,

maximum' ::  (Ord a) => (Num a) => [(a,b)] -> a  
maximum' [] = error "maximum of empty list"  
maximum' [(x,y)] = -1
maximum' (x:xs)   
  | snd x > snd(xs !! maxTail) = 0
  | otherwise = maxTail  
  where maxTail = maximum' xs + 1

我收到这条对我来说毫无意义的错误消息:

newjo.hs:23:25:
Could not deduce (a ~ Int)
from the context (Ord a, Num a)
  bound by the type signature for
             maximum' :: (Ord a, Num a) => [(a, b)] -> a
  at newjo.hs:19:14-47
  `a' is a rigid type variable bound by
      the type signature for maximum' :: (Ord a, Num a) => [(a, b)] -> a
      at newjo.hs:19:14
In the second argument of `(!!)', namely `maxTail'
In the first argument of `snd', namely `(xs !! maxTail)'
In the second argument of `(>)', namely `snd (xs !! maxTail)'`

我需要一些关于如何做到这一点的帮助。

【问题讨论】:

    标签: haskell


    【解决方案1】:

    惯用的方法是使用maximumBy (comparing snd)。

    a ~ Int 消息意味着由于某种原因 Haskell 推断出a 必须是Int,但类型签名并不将其限制为Ints。 As Amos notes in the comments 和 GHC 告诉你它的源位置,这是因为你使用它作为 !! 的第二个参数,这是一个 Int。

    【讨论】:

    • 其实错误是因为'xs!!maxTail',其中maxTail :: a 但是!!需要一个 Int。 -1 适用于任何 Num a
    • @Amos:我想我读得太快了,猜错了。谢谢指正。
    • 也许你应该提到你必须导入Data.Ord才能使用comparing。
    【解决方案2】:

    使用库的惯用方式是使用maximumBy。

    maximumBy :: (a -> a -> Ordering) -> [a] -> a
    

    剩下的就是定义a -> a ->Ordering类型的函数,这样它就知道如何对元素进行排序了。构造Ordering 对象的常用方法是使用

    compare :: (Ord a) => a -> a -> Ordering
    

    【讨论】:

      【解决方案3】:

      目前所提供的解决方案非常优雅,您可能应该在您编写的任何实际代码中使用它们。但这里有一个版本,它使用与您使用的相同模式匹配样式。

      maximum' :: Ord a => [(t, a)] -> (t, a)
      maximum' []     = error "maximum of empty list"
      maximum' (x:xs) = maxTail x xs
        where maxTail currentMax [] = currentMax
              maxTail (m, n) (p:ps)
                | n < (snd p) = maxTail p ps
                | otherwise   = maxTail (m, n) ps
      

      这个解决方案避免了到处乱用索引,而是只跟踪当前最大元素,当整个列表被遍历时返回。避免使用列表进行索引通常被认为是一种好的做法。

      【讨论】:

      • 谢谢。我最喜欢这个,但所有其他解决方案也很有帮助。
      【解决方案4】:

      同样值得注意的是,Haskell 中的元组是Ord 的实例。因此可以对它们进行排序和比较。它们使用字典顺序排序(主要由元组的第一个元素,次要由第二个等),所以以下成立:

      maximum [(1,1),(1,8),(2,1),(2,6)] == (2,6)
      

      如果您想获得具有最大第二个元素的元组。您可以将元组的元素交换为 maximum 函数,然后像这样交换结果元素:

      maximum' :: (Ord a, Ord b) => [(a,b)] -> (a,b)
      maximum' l = swap $ maximum $ map swap l
                   where swap (x, y) = (y, x) 
      

      虽然这两个元组元素都必须是 Ord 的实例。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-01
      • 1970-01-01
      • 2011-01-12
      • 2014-07-21
      • 2020-12-05
      • 2022-08-12
      • 2016-07-18
      • 2021-08-29
      相关资源
      最近更新 更多