Recursion F#使用函数式编程将列表一分为二

Recursion F#使用函数式编程将列表一分为二,recursion,f#,functional-programming,Recursion,F#,Functional Programming,我试图在函数中输入一个列表,它会向我发送一个列表,其中包含使用f#和下面的递归删除的前一半元素,但我一直遇到一个基本情况问题,我就是搞不清楚。有什么想法吗?我使用第二个阴影列表来计算我需要走多远,直到我进入列表的一半(通过一次删除两个元素) 让rec dropHalf listToDrop shadowList= 将阴影列表与 |[]->listToDrop |shadowHead2::shadowHead1::shadowTail->if shadowTail.Length listToDro

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

让rec dropHalf listToDrop shadowList=
将阴影列表与
|[]->listToDrop
|shadowHead2::shadowHead1::shadowTail->if shadowTail.Length listToDrop
|listToDropHead::listToDropTail->dropHalf listToDropTail shadowTail
恐怕我不使用F#,但它类似于ocaml,所以希望下面的内容与您想要的内容接近(可能注释格式已经改变了?!)。这个想法是,当你耗尽阴影时,你就完成了。你的代码就快到了,但是对影子尾巴长度的测试毫无意义


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

以下是一个示例,它实现了你所描述的

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

希望这对您有所帮助

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

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)

一般来说,如果你在列表中调用
Length
,那么很可能有更好的方法来完成你正在做的事情<代码>长度必须迭代整个列表,因此为O(n)


您选择实施的具体原因是什么?有一个更简单的方法来获得给定的List.的一半,这是一个小的函数在一个更大的任务分配,整个事情围绕着以函数编程的方式(我们都来自C++背景)。所以我假设递归。列表中的哪些元素被保留,哪些元素被丢弃,这对您有关系吗?如果您可以使用库函数,只需找到长度并将其减半即可。如果不能,您可能仍然会发现实现这一点是最简单的。显然,当你做练习时,你有时不得不做一些“奇怪”的事情来学习,但在实践中,我所描述的可能是大多数人会做的方式。。。然而,我确实担心,也许你的练习中“更高层次”的部分弄错了。这似乎是一件奇怪的事情——扔掉一半的数据。我不是为了作业。我知道这很奇怪,但我正在尝试以这种方式或其他方式处理递归。她暗示说,事实上,在课堂上做这件事的方式是影印的。谢谢。现在已经很晚了,我不再清晰地思考了。这是非常接近我所寻找的!祝你好运学习fp改进了我在c+java等语言中的代码。要真正点击需要很长时间,但这是值得的,imho。谢谢!在我的问题上似乎有很多困惑,我认为这是因为现在每个人都试图把每一个构造都投入到他们的编程语言中,而现在不同编程方法之间的界限越来越模糊。你使用像Length这样的库并不是纯功能性的
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
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