P02 - 取列表倒数第二个元素
Penultimate element of a list
官方模块:
Problems.P02核心函数:myButLast
← P01 取列表最后一个元素 | P03 取列表第 k 个元素 →
← P01 取列表最后一个元素 | P03 取列表第 k 个元素 →
题目描述
找出列表的倒数第二个元素(penultimate element)。如果列表不足两个元素,返回 Nothing。
函数签名
1myButLast :: [a] -> Maybe a
思路
和 P01 类似,但需要多一个元素的前瞻。模式匹配时有三种情况:
- 空列表
[]或单元素[_]——不足两个,返回Nothing - 正好两个元素
[x, _]——那x就是倒数第二个 - 至少三个元素
(_:xs)——递归处理xs,把问题规模缩小
实现
方法一:标准递归
1myButLast :: [a] -> Maybe a
2myButLast [] = Nothing
3myButLast [_] = Nothing
4myButLast [x, _] = Just x
5myButLast (_:xs) = myButLast xs
前两个模式处理不足两元素的 case;[x, _] 匹配正好两个元素,返回第一个;(_:xs) 丢弃头部,在更短的列表上继续找。
方法二:利用 reverse 和 listToMaybe
1import Data.Maybe (listToMaybe)
2
3myButLast :: [a] -> Maybe a
4myButLast [] = Nothing
5myButLast xs = listToMaybe . drop 1 . reverse $ xs
reverse 反转后倒数第二个变成正数第二个,drop 1 扔掉第一个,再取 listToMaybe。
方法三:使用标准库 init + last
1myButLast :: [a] -> Maybe a
2myButLast [] = Nothing
3myButLast [_] = Nothing
4myButLast xs = Just . last . init $ xs
init 去掉最后一个元素,last 取结果列表的最后一个(即原列表的倒数第二个)。
测试
1>>> myButLast [1,2,3,4]
2Just 3
3
4>>> myButLast ['a'..'z']
5Just 'y'
6
7>>> myButLast ['a']
8Nothing
9
10>>> myButLast []
11Nothing