我是Haskell的新手,正在尝试编写一个非常简单的函数,该函数将每个重复的连续元素收集在单独的子列表下,例如:
f :: Eq a => [a] -> [[a]]
所以:
f [] = []
f [3] = [[3]]
f [1,1,1,3,2,2,1,1,1,1] = [[1,1,1],[3],[2,2],[1,1,1,1]]
我考虑过此功能:
f :: Eq a => [a] -> [[a]]
f [] = []
f (x:[]) = [[x]]
f (x:x':xs) = if x == x' then [[x, x']] ++ (f (xs))
else [[x]] ++ (f (xs))
它似乎不能很好地工作,因为当它到达最后一个元素时,它想将其与连续的元素进行比较,后者显然不存在。
我想收到一个简单的答案(初学者水平),该答案不会与我的有太大不同,纠正我的代码将是最好的。
谢谢。
答案 0 :(得分:2)
问题实际上并不是您所说的,只是您仅硬编码了一个或两个连续元素相等的情况。实际上,您想将任意个相等的连续部分连在一起。 IOW,对于每个元素,您都会弹出相等数量的后续元素。
通常,满足某些条件的列表的开头部分的拆分是span
函数的作用。在这种情况下,应检查的条件是等于您已删除的元素。这样写:
f [] = []
f (x:xs) = (x:xCopies) : f others
where (xCopies,others) = span (==x) xs
在这里,x:xCopies
将等于x
的元素块放在一起(x
本身在前面),将其用作结果的标题块列表,然后您递归剩余的所有元素。
答案 1 :(得分:0)
您的问题是if
的两半都具有相同的结构:它们恰好将一个元素限制在递归调用的前面。这可能是不对的:有时候您想将元素添加到列表的最前面,而其他时候您想将元素与递归调用中已有的元素组合在一起。
相反,您需要在递归调用上进行模式匹配,以获取递归结果中的第一项,然后在前两项匹配时在那个之前。
f :: Eq a => [a] -> [[a]]
f [] = []
f [x] = [[x]]
f (x:xs@(y:_)) | x == y = (x:head):more
| otherwise = [x]:result
where result@(head:more) = f xs