F#使用函数式编程将列表切成两半

时间:2012-05-22 00:53:31

标签: recursion f# functional-programming

我正在尝试在函数中输入一个列表,它向我发送一个列表,其中前半部分元素使用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

4 个答案:

答案 0 :(得分:2)

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类似,所以希望以下内容接近您正在寻找的内容(可能评论格式已更改) ?!)。我的想法是,当你耗尽阴影时,你已经完成了。你的代码几乎就在那里,但阴影尾部的长度测试毫无意义。

我想强调的是,这并不像任何人在现实生活中所写的那样#34;但听起来你似乎正在与一些奇怪的要求作斗争。

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

作为一般经验法则,如果您在列表中调用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

答案 3 :(得分:0)

以下是您所描述的示例。

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() 

希望这有帮助