我有以下函数,它接受一个列表并返回在给定元素n处拆分的两个子列表。但是,我只需要将它分成两半,奇数长度列表具有更大的第一个子列表
splitlist :: [a] -> Int -> ([a],[a])
splitlist [] = ([],[])
splitlist l@(x : xs) n | n > 0 = (x : ys, zs)
| otherwise = (l, [])
where (ys,zs) = splitlist xs (n - 1)
我知道我需要将签名更改为[a] - > ([a],[a]),但在代码中我应该放一些像长度(xs)这样的东西,这样我就不会破坏递归?谢谢。
答案 0 :(得分:7)
你可以使用take and drop:
来做到这一点splitlist :: [a] -> ([a],[a])
splitlist [] = ([],[])
splitlist l = let half = (length(l) +1)`div` 2
in (take half l, drop half l)
或者您可以利用splitAt函数:
splitlist list = splitAt ((length (list) + 1) `div` 2) list
答案 1 :(得分:7)
在真正的程序中你应该使用
splitlist :: [a] -> ([a], [a])
splitlist xs = splitAt ((length xs + 1) `div` 2) xs
(即类似于dreamcrash的回答。)
但是,如果出于学习目的,您正在寻找明确的递归解决方案,请研究一下:
splitlist :: [a] -> ([a], [a])
splitlist xs = f xs xs where
f (y : ys) (_ : _ : zs) =
let (as, bs) = f ys zs
in (y : as, bs)
f (y : ys) (_ : []) = (y : [], ys)
f ys [] = ([], ys)