【问题标题】:F# Cutting a list in half using functional programmingF# 使用函数式编程将列表减半
【发布时间】:2012-05-28 11:59:43
【问题描述】:

我正在尝试在函数中输入一个列表,它会向我发送一个列表,其中包含使用 f# 和以下递归删除的前半部分元素,但我一直遇到一个我无法弄清楚的基本情况问题。有什么想法吗?我正在使用第二个影子列表来计算我需要走多远才能进入列表的一半(通过一次删除两个元素)

let rec dropHalf listToDrop shadowList = 
    match shadowList with
    | [] -> listToDrop
    | shadowHead2::shadowHead1::shadowTail -> if shadowTail.Length<=1 then listToDrop else 
                                    match listToDrop with 
                                    |[] -> listToDrop
                                    |listToDropHead::listToDropTail -> dropHalf listToDropTail shadowTail

【问题讨论】:

  • 您选择实施是否有特定原因?有更简单、更简单的方法来获取给定列表的一半。
  • 嗯,这是一个更大的任务中的一个小函数,整个事情都围绕着以函数式编程方式进行(我们都来自 c++ 背景)。所以我假设递归。
  • 保留列表中的哪些元素以及丢弃哪些元素对您来说是否重要。
  • 如果你可以使用库函数,只要找到长度,将它的一半。如果你不能,你可能仍然会发现实现最简单。显然,在做练习时,你有时必须做一些“奇怪”的事情来学习,但在实践中,我所描述的可能是大多数人会这样做的方式......但是我确实担心你可能会得到一些“更高水平”的部分你的运动错了。这似乎是一件奇怪的事情 - 丢弃了一半的数据。
  • 我不适合分配。我知道这很奇怪,但我正在尝试以这种方式或其他与递归一起使用的方式来实现。事实上,她在课堂上暗示和影子复制的方式。

标签: recursion f# functional-programming


【解决方案1】:
let rec dropHalf listToDrop shadowList = 
    match shadowList with
    | [] -> listToDrop
    | shadowHead2::[] -> listToDrop   (* odd number! *)
    | shadowHead1::shadowHead2::shadowTail -> 
        match listToDrop with 
        | [] -> listToDrop   (* should never happen? *)
        | listToDropHead::listToDropTail -> dropHalf listToDropTail shadowTail

恐怕我不使用 F#,但它类似于 ocaml,因此希望以下内容接近您正在寻找的内容(也许评论格式已更改?!)。这个想法是,当你耗尽阴影时,你就完成了。你的代码差不多了,但是影子尾巴上的长度测试没有意义。

我想强调的是,这不像任何人都会在“现实生活中”写的那样,但听起来你正在与一些奇怪的要求作斗争。

【讨论】:

  • 谢谢。现在已经很晚了,我不再想清楚了。这与我想要的非常接近!
  • 祝你好运。学习 fp 改进了我用 c + java 等语言编写的代码。真正点击需要很长时间,但这是值得的,恕我直言。
【解决方案2】:

因为你使用与原始列表长度相同的影子列表,并以不同的速率从这些列表中移除元素,所以最好创建一个辅助函数:

let dropHalf xs =
    let rec dropHalf' ys zs =
      match ys, zs with
      | _::_::ys', _::zs' -> dropHalf' ys' zs'
      | _, zs' -> zs' (* One half of the shadow list ys *)
    dropHalf' xs xs

如果你不想遍历列表两次,下面的解决方案更简单:

let rec drop n xs =
   match xs, n with
   | _ when n < 0 -> failwith "n should be greater or equals to 0"
   | [], _ -> []
   | _, 0 -> xs
   | _::xs', _ -> drop (n-1) xs'

let dropHalf xs =
    xs |> drop (List.length xs/2)

另一个简单的解决方案需要一些额外的空间,但不必使用递归:

let dropHalf xs = 
    let xa = Array.ofList xs
    xa.[xa.Length/2..] |> List.ofArray

【讨论】:

    【解决方案3】:

    作为一般经验法则,如果您在列表中调用Length,那么很可能有更好的方法来做您正在做的事情。 Length 必须迭代整个列表,因此是 O(n)。

    let secondHalf list =
        let rec half (result : 'a list) = function
            | a::b::sx -> half result.Tail sx
            // uncomment to remove odd value from second half
            // | (a::sx) -> result.Tail 
            | _ -> result
    
        half list list
    

    【讨论】:

    • 谢谢!似乎对我的问题有很多困惑,我认为这是因为现在每个人都试图将每个结构都投入到他们的编程语言中,而不同编程方法之间的界限越来越模糊。
    【解决方案4】:

    这是您所描述的示例。

    open System
    open System.Collections.Generic
    
    let items = seq { 1 .. 100 } |> Seq.toList
    
    let getBackOfList ( targetList : int list) = 
        if (targetList.Length = 0) then 
            targetList
        else
            let len = targetList.Length
            let halfLen = len / 2
            targetList |> Seq.skip halfLen |> Seq.toList
    
    let shortList = items |> getBackOfList
    
    ("Len: {0}", shortList.Length) |> Console.WriteLine
    
    let result = Console.ReadLine() 
    

    希望对你有帮助

    【讨论】:

    • 您使用的库,如 Length,这不是纯粹的功能
    猜你喜欢
    • 2019-02-12
    • 1970-01-01
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多