P14 - 复制每个元素
Duplicate elements of a list
官方模块:
Problems.P14核心函数:dupli
← P13 直接实现游程编码 | P15 每个元素重复 N 次 →
题目描述
将列表中的每个元素复制一份,即每个元素在结果中连续出现两次。
函数签名
1dupli :: [a] -> [a]
思路
遍历列表,对每个元素输出两次:x : x : dupli xs。
实现
方法一:递归
1dupli :: [a] -> [a]
2dupli [] = []
3dupli (x:xs) = x : x : dupli xs
最直接的递归,每个元素放两次。
方法二:concatMap
1dupli :: [a] -> [a]
2dupli = concatMap (\x -> [x, x])
或者更简洁地:
1dupli = concatMap (replicate 2)
concatMap 详解concatMap f xs = concat (map f xs)——先 map 再 concat,一步完成"映射并展平"。
拆解 concatMap (\x -> [x, x]) [1,2,3]:
1第一步 map: f 1 = [1,1] f 2 = [2,2] f 3 = [3,3]
2 → [[1,1], [2,2], [3,3]]
3
4第二步 concat: 拼接所有子列表 → [1,1,2,2,3,3]
所以 concatMap (\x -> [x, x]) 的意思是:对每个元素,生成一个包含该元素两次的小列表,再把所有小列表拼成一个大列表。
如果 dupli 用 map 实现(忘记 concat):
1map (\x -> [x,x]) [1,2,3] → [[1,1],[2,2],[3,3]] -- 类型是 [[Int]],不对
结果类型不对——map 返回的是列表的列表。concatMap 相当于 map 之后再 concat,一步到位把嵌套展平。
方法三:列表推导
1dupli xs = [x | x <- xs, _ <- [1, 2]]
_ <- [1, 2] 让每个 x 被取两次。
测试
1>>> dupli [1, 2, 3]
2[1,1,2,2,3,3]
3
4>>> dupli []
5[]
6
7>>> dupli "hi"
8"hhii"