P07 - 展平嵌套列表

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

P07 - 展平嵌套列表

Flatten a nested list structure

官方模块: Problems.P07 核心函数: flatten


← P06 判断回文 | P08 去除连续重复元素 →



← P06 判断回文 | P08 去除连续重复元素 →


题目描述

展平一个嵌套列表结构。需要自定义 NestedList 数据类型,可以是单个元素 Elem a 或子列表 List [NestedList a]

函数签名

1flatten :: NestedList a -> [a]

NestedList 数据类型

要表示 “嵌套列表”,普通列表不够用——[a] 只能存储同一类型的元素,而嵌套列表在任意深度都可能是一个元素或一个子列表。

Haskell 的代数数据类型(ADT)正是解决这类问题的利器:

1data NestedList a
2  = Elem a
3  | List [NestedList a]
4  deriving (Show, Eq)

这定义了一个递归类型:

例如 List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]] 表示 [1,[2,[3,4],5]]

思路

递归遍历 NestedList

这正是 flatten 的语义:遇到叶子就包裹成列表,遇到内部节点就展平后合并。

实现

方法一:递归模式匹配

1flatten :: NestedList a -> [a]
2flatten (Elem x)   = [x]
3flatten (List [])  = []
4flatten (List (x:xs)) = flatten x ++ flatten (List xs)

这版写法最显式地展示了递归结构:

方法二:concatMap(更简洁)

1flatten :: NestedList a -> [a]
2flatten (Elem x)  = [x]
3flatten (List xs) = concatMap flatten xs

concatMap flatten xs = concat (map flatten xs),先对每个子元素 flatten,再把所有结果拼成一个列表。

方法三:纯 fold 风格

1flatten :: NestedList a -> [a]
2flatten (Elem x)  = [x]
3flatten (List xs) = foldMap flatten xs

foldMap 来自 Data.Foldable,它用 Monoidmappend(对列表就是 ++)来组合结果。这里 foldMap flatten xs 等价于 concatMap flatten xs

理解 NestedList 的内存结构

1List [
2  Elem 1,
3  List [
4    Elem 2,
5    List [Elem 3, Elem 4],
6    Elem 5
7  ]
8]

可以看作树形结构:

1        List
2       / |  \
3      1 List  ...
4        / | \
5       2  List  5
6         /  \
7        3    4

flatten 就是做了一次前序遍历,把所有叶子节点的值收集到列表中。

测试

 1>>> flatten (Elem 5)
 2[5]
 3
 4>>> flatten (List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]])
 5[1,2,3,4,5]
 6
 7>>> flatten (List [])
 8[]
 9
10>>> flatten (List [Elem 1, Elem 2, Elem 3])
11[1,2,3]

要点总结

参考


← P06 判断回文 | P08 去除连续重复元素 →