【问题标题】:Simple haskell splitlist简单的haskell拆分列表
【发布时间】:2020-12-28 17:28:15
【问题描述】:

我有以下函数,它接受一个列表并返回在给定元素 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]),但是我应该在代码中的什么位置放置诸如 length(xs) 之类的内容,以免中断递归?

【问题讨论】:

标签: haskell


【解决方案1】:

在一个真正的程序中你可能应该使用

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)

【讨论】:

  • 顺便说一句,如果是因为我在键盘上编译,我不这样做,但是 length xs + 1 'div' 2 必须放 length (xs + 1) 'div' 2跨度>
  • 不,这是因为我没有测试我的代码。感谢您发现它。
  • 如果列表很长,龟兔赛跑的解决方案比基于splitAt 的解决方案要好得多。它执行一次而不是两次,它懒惰地生成第一个组件。我不确定你为什么推荐其他实现。
【解决方案2】:

您可以使用 take 和 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-05
    • 1970-01-01
    • 1970-01-01
    • 2020-03-18
    • 1970-01-01
    • 2011-11-16
    • 2018-10-11
    • 1970-01-01
    相关资源
    最近更新 更多