haskell中每个元素的所有后继者的映射

时间:2014-11-12 09:38:39

标签: haskell list-comprehension

给定一系列元素,我想找到每个元素的所有直接后继的列表:

示例:

"AABAABAAC"

应返回类似(使用Data.Map)的内容:

fromList [('A',"ABABA"), ('B',"AA"), ('C', "")]

我知道fromListWith函数,但我似乎无法使列表理解正确:

succs :: Ord a => [a] -> M.Map a [a]
succs xs = M.fromListWith (++) [(x, ???) | ??? ]

2 个答案:

答案 0 :(得分:3)

这有帮助吗?

succs xs@(_:xss) = M.fromListWith (++) $ zip xs (map (:[]) xss ++ [[]])

我认为它返回('A',"ABABAC")...,您的示例没有C

(:[])

的无点版本
singleton :: a -> [a]
singleton x = [x]

我是如何得到这个解决方案的?我发现斐波那契数字的这个定义令人着迷:[1] [2]

fibs = fibs = 0:1:zipWith (+) fibs (tail fibs)

类似的事情可以将每个元素与其后继者配对:

let x = "AABAABAAC"
zip x (tail x)
[('A','A'),('A','B'),('B','A'),('A','A'),('A','B'),('B','A'),('A','A'),('A','C')]

此类型几乎匹配

的输入
M.fromListWith :: Ord k => (a -> a -> a) -> [(k, a)] -> M.Map k a

现在将字符转换为单个列表并添加一个空列表以禁止('C',"")

答案 1 :(得分:1)

您可以将问题分成两部分。首先,找到列表中两个元素之间的边缘。

edges :: [a] -> [(a, a)]
edges (x:y:zs) = (x,y):edges (y:zs)
edges _ = []

然后使用fromListWith为所有项目的直接后继者构建地图。

succs :: Ord a => [a] -> M.Map a [a]
succs = M.fromListWith (++) . map (\(x,y) -> (x,[y])) . edges

这并不能完全满足您的需求。 'C'没有条目,因为它没有立即接班人。

succs "AABAABAAC" = fromList [('A',"CABABA"),('B',"AA")]

相反,我们可以制作一个不太通用的edges版本,其中包含列表中最后一项的项目。

succs :: Ord a => [a] -> M.Map a [a]
succs = M.fromListWith (++) . edges
    where
        edges (x:y:zs) = (x,[y]):edges (y:zs)
        edges (x:zs)   = (x,[] ):edges zs
        edges _ = []