以语义方式填充元组列表

时间:2015-07-08 16:28:54

标签: haskell list-comprehension

我正在编写一段代码,我必须处理元组列表,其中“键”(元组的fst)的顺序和名称都与某个模板匹配。我正在通过验证和(如果需要)根据输入生成有效列表来实现容错。

这是我的意思的一个例子:

给定密钥模板["hello", "world", "this", "is", "a", "test"]和列表[("hello", Just 1), ("world", Just 2), ("test", Just 3)],将其传递给我的函数validate会导致验证失败 - 因为密钥的顺序和值会与模板不匹配。

验证失败后,我想生成一个新列表,看起来像[("hello", Just 1), ("world", Just 2), ("this", Nothing), ("is", Nothing), ("a", Nothing), ("test", Just 3)]

我尝试使用(不完整的)列表理解来执行最后一步:

[(x, y) | x <- template, y <- l]

(显然,这缺少了空项将被Nothing替换的步骤,并且假设输入类型为[(String, Maybe Int)])。

这样做最简单的语义方式是什么?

1 个答案:

答案 0 :(得分:1)

你基本上想要映射一个函数到你的字符串列表(你称之为&#34;模板&#34;),即

的功能
  • 采用字符串xs
  • 返回
    • (xs, Just n)如果整数n与您的&#34;列表中的xs相关联以验证&#34;,
    • (xs, Nothing)否则。

这是一种可能的方法:

import Data.List     ( lookup )
import Control.Monad ( join )

consolidate :: [String] -> [(String, Maybe Int)] -> [(String, Maybe Int)]
consolidate temp l = map (\xs -> (xs, join $ lookup xs l)) temp

但是,如果您构建一个Map来保存关联列表的键值对(&#34;列表以验证&#34;),您将获得更快的查找速度:

import qualified Data.Map as M
import Data.Maybe (maybe)

consolidate :: [String] -> [(String, Maybe Int)] -> [(String, Maybe Int)]
consolidate temp l = map (\cs -> (cs, M.lookup cs $ fromList' l)) temp

fromList' :: Ord a => [(a, Maybe b)] -> M.Map a b
fromList' xs = foldr insertJust M.empty xs

insertJust :: Ord a => (a, Maybe b) -> M.Map a b -> M.Map a b
insertJust (xs, maybeVal) mp = maybe mp (\n -> M.insert xs n mp) maybeVal

在GHCi中:

λ> let myTemplate = ["hello", "world", "this", "is", "a", "test"]
λ> let myList = [("hello", Just 1), ("world", Just 2), ("test", Just 3)]
λ> consolidate myTemplate myList 
[("hello",Just 1),("world",Just 2),("this",Nothing),("is",Nothing),("a",Nothing),("test",Just 3)]