P08 - 去除连续重复元素

2026-09-07 00:00    #Haskell   #99题   #列表  

P08 - 去除连续重复元素

Eliminate consecutive duplicates of list elements

官方模块: Problems.P08 核心函数: compress


← P07 展平嵌套列表 | P09 将连续重复元素打包成子列表 →



← P07 展平嵌套列表 | P09 将连续重复元素打包成子列表 →


题目描述

去除列表中连续重复的元素,每组连续相同元素只保留一个。元素的相对顺序不变。

函数签名

1compress :: Eq a => [a] -> [a]

需要 Eq a 约束来比较元素是否相等。

思路

遍历列表,只保留与前一个元素不同的那些元素。即:

实现

方法一:模式匹配 + 递归

1compress :: Eq a => [a] -> [a]
2compress []       = []
3compress [x]      = [x]
4compress (x:y:xs)
5  | x == y    = compress (x:xs)
6  | otherwise = x : compress (y:xs)

最直接的递归版本。[x] 模式处理单元素列表(避免不必要的对比),双元素 (x:y:xs) 模式决定去重还是保留。

方法二:使用 map + group

1import Data.List (group)
2
3compress :: Eq a => [a] -> [a]
4compress = map head . group

group 把连续重复元素打包成子列表("aaaabccaadeeee"["aaaa","b","cc","aa","d","eeee"]),map head 取每个子列表的第一个元素。

这是一个经典的 Haskell 单行惯用法

方法三:使用 foldr

1compress :: Eq a => [a] -> [a]
2compress = foldr go []
3  where
4    go x [] = [x]
5    go x acc
6      | x == head acc = acc
7      | otherwise     = x : acc

从右向左 fold,如果当前元素等于已积累结果的头部,就跳过它。

理解 group 的工作方式

Data.List.group 是 P09 要解决的问题。但在 P08 中我们可以用它来简化实现:

1输入: "aaaabccaadeeee"
2group: ["aaaa","b","cc","aa","d","eeee"]
3map head: "abcade"

每一组连续重复元素被压成一个单元素,恰好完成去重。

测试

 1>>> compress "aaaabccaadeeee"
 2"abcade"
 3
 4>>> compress [1,1,2,2,3,3,3,1,1]
 5[1,2,3,1]
 6
 7>>> compress []
 8[]
 9
10>>> compress "a"
11"a"

注意最后的 1 不会被去掉,因为 compress 只去连续重复,而这两个 12,3 隔开了。

参考


← P07 展平嵌套列表 | P09 将连续重复元素打包成子列表 →