在列表中对连续重复项进行分组?

时间:2016-11-15 22:38:18

标签: list haskell

非常基本,但我发现问题令人沮丧。我正在尝试对列表中的连续元素进行分组:

myList = [1,2,3,4,4,4,5]

变为

myList = [[1],[2],[3],[4,4,4],[5]]

这是我尝试将foldr与累加器一起使用:

print $ foldr (\ el acc -> if el /= head (head acc) then el ++ (head acc) else acc) [['a']] myList

我不明白为什么我收到以下错误:

Couldn't match expected type ‘[a0]’ with actual type ‘Int’
In the expression: 'a'
In the expression: ['a']
In the second argument of ‘foldr’, namely ‘[['a']]’

任何建议都会很棒!

3 个答案:

答案 0 :(得分:2)

在列表上写一个折叠要求我们只回答两种情况:K * N(空列表,或“nil”)和[](一个元素后面跟一个列表或“cons”)

列表为空时的答案是什么?让我们说答案也是一个空列表。因此:

x:xs

列表不为空时的答案是什么?这取决于我们已经积累了什么。可以说我们已经积累了一个小组。我们知道群体是非空的。

nilCase = []

如果consCase x ((g11:_):gs) ,我们会将其添加到群组中。否则我们开始一个新的小组。因此:

x == g11

如果我们还没有累积任何群组怎么办?然后我们只创建一个新组。

consCase x ggs@(g1@(g11:_):gs)
  | x == g11  = (x:g1):gs
  | otherwise = [x]:ggs

我们可以将这三个案例合并为两个:

consCase x [] = [[x]]

然后所需的折叠就是:

consCase x ggs
  | g1@(g11:_):gs <- ggs, x == g11 = (x:g1):gs
  | otherwise                      = [x]:ggs

答案 1 :(得分:1)

使用foldr,应该是:

group :: (Eq a) => [a] -> [[a]]
group = foldr (\x acc -> if head acc == [] || head (head acc) == x then (x:head acc) : tail acc else [x] : acc) [[]]

答案 2 :(得分:1)

您的案例类型为!,您正在尝试构建[[Char]]类型的值。我们的基本情况应该是一个空列表,我们将在每个步骤中添加列表元素。

让我们看看你接下来写的匿名函数。请注意,由于基于您在累加器中的当前[[Int]]的类型,我们将失败(它们必须返回相同类型的值,并且与累加器的类型相同。如果我们将更好,更清洁模式匹配累加器并在每种情况下以不同方式应用函数:

if

当我们遇到基本情况时,我们应该添加包含在列表中的元素:

func :: Eq a => [a] -> [[a]]
func = foldr f []
  where f x []        = undefined
        f x (b@(b1:_):bs)
            | x == b1   = undefined
            | otherwise = undefined

接下来,我们将处理非空列表。如果x等于列表头部的下一个头部,我们应该将其添加到该列表中。否则,我们会

f x [] = [[x]]

把这些放在一起,我们有:

f x (b@(b1:_):bs)
  | == b1   = (x:b):bs
  | = [x]:b:bs

将问题解决后,使用lambda函数更紧凑地重写它会容易得多。请注意,func :: Eq a => [a] -> [[a]] func = foldr f [] where f x [] = [[x]] f x (b@(b1:_):bs) | x == b1 = (x:b):bs | otherwise = [x]:b:bs head只是[[]],因此我们可以将空列表案例和相等案例作为一个操作处理。因此,我们可以改写:

[]

但是,此解决方案最终需要使用func :: (Eq a) => [a] -> [[a]] func = foldr (\x (b:bs) -> if b == [] || x == head b then (x:b):bs else [x]:b:bs) [[]] ,因为我们必须模式匹配累加器的所有版本。