P17 - 在 N 处切分列表
Split a list into two parts
官方模块:
Problems.P17核心函数:split
← P16 每隔 N 个删除一个元素 | P18 提取子列表 →
题目描述
在指定的位置 N 处将列表切分为两个子列表。前一部分包含前 N 个元素,后一部分包含剩余元素。
函数签名
1split :: [a] -> Int -> ([a], [a])
思路
take n xs取前 N 个drop n xs取剩余部分
实现
方法一:take + drop
1split :: [a] -> Int -> ([a], [a])
2split xs n = (take n xs, drop n xs)
标准库 splitAt 做的就是这件事,这就是它的实现方式。
如果 N 大于列表长度,take 返回整个列表,drop 返回空列表,行为安全。
方法二:递归
1split :: [a] -> Int -> ([a], [a])
2split xs 0 = ([], xs)
3split [] _ = ([], [])
4split (x:xs) n = let (first, second) = split xs (n - 1)
5 in (x : first, second)
不用 take/drop,纯递归实现。N 递减到 0 时停止取元素。
方法三:使用标准库
1import Data.List (splitAt)
2
3split :: [a] -> Int -> ([a], [a])
4split = splitAt
标准库的 splitAt 就是 P17 的官方解法。
与 splitAt 的关系
实际上 P17 的 split 就是标准库 splitAt 的重新实现。splitAt 在 GHC.List 中的定义就是:
1splitAt n xs = (take n xs, drop n xs)
测试
1>>> split "abcdefghik" 3
2("abc","defghik")
3
4>>> split [1,2,3] 5
5([1,2,3],[])
6
7>>> split [] 3
8([],[])