比较对列表中的元素

时间:2010-11-04 04:26:19

标签: list haskell tuples

我无法搞清楚这个功能:

  

定义一个带有对列表的函数maybeA :: [(String, a)] -> Maybe (String, a, a)。如果输入列表有两对(a1, b1), (a2, b2),使得a1 = a2,则该函数返回包含a1和b1,b2的元组。否则它返回Nothing。示例:maybeA [("a", 1), ("b", 2), ("b", 3)]将返回Just ("b", 2, 3)

任何提示?

2 个答案:

答案 0 :(得分:3)

这是一个“组合方法” - 将问题分解为简单的小步骤,然后使用函数组合逐个应用这些步骤:

import Data.List (sort, groupBy)
import Data.Maybe (listToMaybe)
import Data.Function (on)

maybeA = fmap formatAnswer . listToMaybe . dropWhile (null . drop 1) .
         groupBy ((==) `on` fst) . sort
  where
    formatAnswer ((a, b1):(_, b2):_) = (a, b1, b2)

一些注意事项:

  • fmap将函数应用于Maybe内的值(如果存在)。 (fmap也可以在许多其他类型上以类似的方式工作。)
  • (==)`` fst`测试两个元组的第一个元素是否相等。
  • sort比较元组中的两个元素,但它使用字典顺序。所以它可以在这里工作,但它有时会改变b1b2的顺序。如果这对你来说是个问题, 请改用sortBy (comparing fst)sortBy位于Data.List模块中,comparing位于Data.Function模块中。

答案 1 :(得分:1)

如果您只是在寻找前两次出现的情况,其中两对具有相同的前两个元素,那么以下定义将起作用:

maybeA :: [(String, a)] -> Maybe (String, a, a)
maybeA = maybeA' []
  where
    maybeA' _ []           = Nothing
    maybeA' as ((x,y):xys) = 
      case lookup x as of
        Just y' -> Just (x,y,y')
        Nothing -> maybeA' ((x,y):as) xys

注意,如果您传递一个包含(a1, b1)(a2, b2)(a3, b3)的列表,其中a1 == a2a2 = = a3,它只返回Just (a1, b1,b2)而不是Just (a1, b1,b2,b3)(甚至不是同一类型)。

设计一个执行此操作的函数作为练习: - )