List F#:递归函数:将列表分成两个相等的部分

List F#:递归函数:将列表分成两个相等的部分,list,recursion,split,f#,List,Recursion,Split,F#,我在使用拆分和合并排序时遇到一些错误。(注意:这是一个格式化的赋值,要求每个函数具有特定的输入和输出类型) 这是我现在的代码: (* val split : l:'a list -> 'a list * 'a list *) let split (l:'a list -> 'a list * 'a list) = let rec splitInner = function | [],[] -> [],[] | x::xs, acc -&

我在使用拆分和合并排序时遇到一些错误。(注意:这是一个格式化的赋值,要求每个函数具有特定的输入和输出类型)

这是我现在的代码:

(* val split : l:'a list -> 'a list * 'a list *)
let split (l:'a list -> 'a list * 'a list) = 
    let rec splitInner = function
        | [],[] -> [],[]
        | x::xs, acc ->
            if xs.Length>(acc.Length) then splitInner (xs x::acc)
            else xs acc
    splitInner (l, acc)

error FS0001: This expression was expected to have type
    'a list * 'b list    
but here has type
    'c list

(* val merge : 'a list * 'a list -> 'a list when 'a : comparison *)
let rec merge l = 
    match l with
    | (xs,[])->xs
    | ([],ys)->ys
    | (x::xs, y::yr) ->
        if x<=y then x::merge(xr,y::yr)
        else y::merge(x::xr,yr)

(* val mergesort : l:'a list -> 'a list when 'a : comparison *)
let rec mergesort l = 
    match l with
    | [] -> []
    | [x] -> [x]
    | xs -> let (ys,zs) = split xs then merge(mergesort ys, mergesort zs)
示例:

> halve [1..10];;
val it : int list * int list = ([1; 2; 3; 4; 5], [6; 7; 8; 9; 10])
> halve [1..9];;
val it : int list * int list = ([1; 2; 3; 4], [5; 6; 7; 8; 9])
这个是如何工作的

比赛有三种模式

| []           which only matches when the input list is empty
| [x]          which only matches when there is only one item in the list
| x::y::tail   which matches all the other patterns 
这一个表示我们不需要知道列表的长度,因为如果列表中至少有两个项目
|x::y::tail
,则将一个项目放入列表一,另一个放入列表二。重复此操作,直到列表中有一项或没有项为止。如果列表中有一项,则将其放入第一个列表并重复。现在输入列表为空,因此返回两个列表

第三种变体

由谁使用

这个函数将函数传递给内部函数。函数是
(fun x->x)
,内部函数在
cont
参数中接收它。这个还有三种匹配模式

| []   only matches on empty list  
| l    only matches on list with one item  
| h::t matches when there are two or more items in the list.  
但是,由于它为每个递归调用传递一个函数,因此在通过递归函数传递列表之前,不会对构建的函数进行求值。它还使用一个计数器,但倒计时为0,以避免必须传递额外的参数。这是一种高级编码,所以不要花太多时间试图理解它,但要注意,因为函数是一流的,所以这是可能的

与前几天不同的第四种变化

let split lst = 
    let rec helper lst l1 l2 ctr =
        match lst with
        | [] -> l1, l2 // return accumulated lists
        | x::xs -> 
            if ctr%2 = 0 then 
                helper xs (x::l1) l2 (ctr+1) // prepend x to list 1 and increment
            else 
                helper xs l1 (x::l2) (ctr+1) // prepend x to list 2 and increment
    helper lst [] [] 0
我是如何创建split的

从格式开始

let funXYZ list =
    let rec funXYZInner list acc =
        match list with
        | head :: tail ->
            let acc = (somefunc head) :: acc
            funXYZInner tail acc
        | [] -> acc
    funXYZInner list []
将函数命名为split

let split list =
    let rec splitInner l acc =
        match l with
        | head :: tail ->
            let acc = (somefunc head) :: acc
            splitInner tail acc
        | [] -> acc
    split list []
现在我知道我需要一个输入列表和两个输出列表,在元组中有两个输出列表

let split l =
    let rec splitInner l list1 list2 =
        match l with
        | head :: tail ->
            let list1 = (somefunc head)
            let list2 = (somefunc head)
            splitInner tail list1 list2
        | [] -> (list1, list2)
    split l [] []
因为拆分会将列表一分为二,所以可以在遍历列表之前计算出

let split l =
    let listMid = (int)((length l)/2)
    let rec splitInner l list1 list2 =
        match l with
        | head :: tail ->
            let list1 = (somefunc head)
            let list2 = (somefunc head)
            splitInner tail list1 list2
        | [] -> (list1, list2)
    split l [] []
要将其转换为条件,我们需要一个计数器。因此,在
splitInner l listMid 0[][]
中将计数器初始化为
0
,并将其传递给匹配模式。因为对于最后一个匹配模式,我们不关心计数的值是多少,所以使用了
\uuu

我们还需要知道将计数器与什么进行比较,即
listMid
,以便将其传递到
splitInner

每次使用磁头时,也要增加计数器

let split l =
    let listMid = (int)((length l)/2)
    let rec splitInner l listMid counter list1 list2 =
        match (l ,counter) with
        | (head :: tail, c) ->
            let list1 = (somefunc head)
            let list2 = (somefunc head)
            let counter = counter + 1
            splitInner tail listMid counter list1 list2
        | ([],_) -> (list1, list2)
    splitInner l listMid 0 [] []
现在添加条件

let split l =        
    let listMid = (int)((length l)/2)
    let rec splitInner l listMid counter list1 list2 =
        match (l,counter) with
        | (head :: tail, c) ->
            if c < listMid then
                let list1 = head :: list1
                let counter = counter + 1
                splitInner tail listMid counter list1 list2
            else
                let list2 = head :: list2
                let counter = counter + 1
                splitInner tail listMid counter list1 list2
        | ([],_)-> (list1, list2)
    splitInner l listMid 0 [] []
并在返回结果之前反转列表

let split l =
    let listMid = (int)((length l)/2)
    let rec splitInner l listMid counter list1 list2 =
        match (l, counter) with
        | (x :: xs, c) ->
            if c < listMid then
                let list1 = x :: list1
                let counter = counter + 1
                splitInner xs listMid counter list1 list2
            else
                let list2 = x :: list2
                let counter = counter + 1
                splitInner xs listMid counter list1 list2
        | ([],_)-> (reverse list1, reverse list2)
    splitInner l listMid 0 [] []
让我们分开l=
让listMid=(int)((长度l)/2)
让rec拆分内部l listMid计数器list1 list2=
将(l,计数器)与
|(x::xs,c)->
如果c(反向列表1,反向列表2)
拆分内部l listMid 0[][]

您的Edit3仍有两个问题:

第一个是由编译器标记的,当您调用
splitInner(l0[][])
时。这里不需要使用任何括号

这将编译并显示不正确的结果:

(* val split : l:'a list -> 'a list * 'a list *)
let split l = 
    let rec splitInner l counter list1 list2 =
        match (l, counter) with
        | (x::xs, c) ->
            if c < (l.Length/2) then
                let list1 = x :: list1
                let counter = counter+1
                splitInner xs counter list1 list2
            else
                let list2 = x :: list2
                let counter = counter+1
                splitInner xs counter list1 list2
        | ([],_) -> ((reverse list1), (reverse list2))
    splitInner l 0 [] []

split [1;2;3;4;5;6;7;8;9;10]

> split [1;2;3;4;5;6;7;8;9;10];;
val it : int list * int list = ([1; 2; 3], [4; 5; 6; 7; 8; 9; 10])
(*val split:l:'a list->'a list*'a list*)
设拆分l=
让rec拆分内部l计数器列表1列表2=
将(l,计数器)与
|(x::xs,c)->
如果c<(l.长度/2),则
让list1=x::list1
设计数器=计数器+1
拆分内部xs计数器列表1列表2
其他的
让list2=x::list2
设计数器=计数器+1
拆分内部xs计数器列表1列表2
|([],u-)>((反向列表1),(反向列表2))
拆分内部l 0[][]
拆分[1;2;3;4;5;6;7;8;9;10]
>分裂[1;2;3;4;5;6;7;8;9;10];;
val-it:int-list*int-list=([1;2;3],[4;5;6;7;8;9;10])
错误是因为在
行中,如果c<(l.Length/2),则每次都要与不同的列表进行比较

让我们看看每次递归调用都会发生什么:

First call to `splitInner`
Parameters
    l = [1;2;3;4;5;6;7;8;9;10]
    counter = 0
    list1 = []
    list2 = []

Values     
    l.Length / 2 = 5
    x = 1
    xs = [2;3;4;5;6;7;8;9;10]
    c = 0
    c < l.Length/2 = True


Second call to `splitInner`
Parameters
    l = [2;3;4;5;6;7;8;9;10]
    counter = 1
    list1 = [1]
    list2 = []

Values     
    l.Length / 2 = 4
    x = 2
    xs = [3;4;5;6;7;8;9;10]
    c = 1
    c < l.Length/2 = True


Third call to `splitInner`
Parameters
    l = [3;4;5;6;7;8;9;10]
    counter = 2
    list1 = [2;1]
    list2 = []

Values     
    l.Length / 2 = 4
    x = 3
    xs = [4;5;6;7;8;9;10]
    c = 2
    c < l.Length/2 = True


Third call to `splitInner`
Parameters
    l = [4;5;6;7;8;9;10]
    counter = 3
    list1 = [3; 2;1]
    list2 = []

Values     
    l.Length / 2 = 3
    x = 4
    xs = [5;6;7;8;9;10]
    c = 3
    c < l.Length/2 = False
对'splitInner'的第一次调用`
参数
l=[1;2;3;4;5;6;7;8;9;10]
计数器=0
列表1=[]
列表2=[]
价值观
l、 长度/2=5
x=1
xs=[2;3;4;5;6;7;8;9;10]
c=0
c
您需要的是与原始列表中计算的“固定”值进行比较

(* val split : l:'a list -> 'a list * 'a list *)
let split (l: 'a list) =
    let middle = l.Length / 2

    let rec splitInner l counter list1 list2 =
        match (l, counter) with
        | (x::xs, c) ->
            if c < middle then
                let list1 = x :: list1
                let counter = counter+1
                splitInner xs counter list1 list2
            else
                let list2 = x :: list2
                let counter = counter+1
                splitInner xs counter list1 list2
        | ([],_) -> ((reverse list1), (reverse list2))

    splitInner l 0 [] []

split [1;2;3;4;5;6;7;8;9;10]
val it : int list * int list = ([1; 2; 3; 4; 5], [6; 7; 8; 9; 10])
(*val split:l:'a list->'a list*'a list*)
让我们分开(l:'列表)=
让中间=l.长度/2
让rec拆分内部l计数器列表1列表2=
将(l,计数器)与
|(x::xs,c)->
如果c((反向列表1),(反向列表2))
拆分内部l 0[][]
拆分[1;2;3;4;5;6;7;8;9;10]
val-it:int-list*int-list=([1;2;3;4;5]、[6;7;8;9;10])
提出了许多将列表分成两部分的方法,下面是我在学习mergeSort时学到的另一种方法(我相信这是最简单的方法之一):


我认为你输入了一个列表和r
let split l =        
    let listMid = (int)((length l)/2)
    let rec splitInner l listMid counter list1 list2 =
        match (l,counter) with
        | (head :: tail, c) ->
            if c < listMid then
                let list1 = head :: list1
                let counter = counter + 1
                splitInner tail listMid counter list1 list2
            else
                let list2 = head :: list2
                let counter = counter + 1
                splitInner tail listMid counter list1 list2
        | ([],_)-> (list1, list2)
    splitInner l listMid 0 [] []
let split l =
    let listMid = (int)((length l)/2)
    let rec splitInner l listMid counter list1 list2 =
        match (l,counter) with
        | (x::xs, c) ->
            if c < listMid then
                let list1 = x :: list1
                let counter = counter + 1
                splitInner xs listMid counter list1 list2
            else
                let list2 = x :: list2
                let counter = counter + 1
                splitInner xs listMid counter list1 list2
        | ([],_)-> (list1, list2)
    splitInner l listMid 0 [] []
let split l =
    let listMid = (int)((length l)/2)
    let rec splitInner l listMid counter list1 list2 =
        match (l, counter) with
        | (x :: xs, c) ->
            if c < listMid then
                let list1 = x :: list1
                let counter = counter + 1
                splitInner xs listMid counter list1 list2
            else
                let list2 = x :: list2
                let counter = counter + 1
                splitInner xs listMid counter list1 list2
        | ([],_)-> (reverse list1, reverse list2)
    splitInner l listMid 0 [] []
(* val split : l:'a list -> 'a list * 'a list *)
let split l = 
    let rec splitInner l counter list1 list2 =
        match (l, counter) with
        | (x::xs, c) ->
            if c < (l.Length/2) then
                let list1 = x :: list1
                let counter = counter+1
                splitInner xs counter list1 list2
            else
                let list2 = x :: list2
                let counter = counter+1
                splitInner xs counter list1 list2
        | ([],_) -> ((reverse list1), (reverse list2))
    splitInner l 0 [] []

split [1;2;3;4;5;6;7;8;9;10]

> split [1;2;3;4;5;6;7;8;9;10];;
val it : int list * int list = ([1; 2; 3], [4; 5; 6; 7; 8; 9; 10])
First call to `splitInner`
Parameters
    l = [1;2;3;4;5;6;7;8;9;10]
    counter = 0
    list1 = []
    list2 = []

Values     
    l.Length / 2 = 5
    x = 1
    xs = [2;3;4;5;6;7;8;9;10]
    c = 0
    c < l.Length/2 = True


Second call to `splitInner`
Parameters
    l = [2;3;4;5;6;7;8;9;10]
    counter = 1
    list1 = [1]
    list2 = []

Values     
    l.Length / 2 = 4
    x = 2
    xs = [3;4;5;6;7;8;9;10]
    c = 1
    c < l.Length/2 = True


Third call to `splitInner`
Parameters
    l = [3;4;5;6;7;8;9;10]
    counter = 2
    list1 = [2;1]
    list2 = []

Values     
    l.Length / 2 = 4
    x = 3
    xs = [4;5;6;7;8;9;10]
    c = 2
    c < l.Length/2 = True


Third call to `splitInner`
Parameters
    l = [4;5;6;7;8;9;10]
    counter = 3
    list1 = [3; 2;1]
    list2 = []

Values     
    l.Length / 2 = 3
    x = 4
    xs = [5;6;7;8;9;10]
    c = 3
    c < l.Length/2 = False
(* val split : l:'a list -> 'a list * 'a list *)
let split (l: 'a list) =
    let middle = l.Length / 2

    let rec splitInner l counter list1 list2 =
        match (l, counter) with
        | (x::xs, c) ->
            if c < middle then
                let list1 = x :: list1
                let counter = counter+1
                splitInner xs counter list1 list2
            else
                let list2 = x :: list2
                let counter = counter+1
                splitInner xs counter list1 list2
        | ([],_) -> ((reverse list1), (reverse list2))

    splitInner l 0 [] []

split [1;2;3;4;5;6;7;8;9;10]
val it : int list * int list = ([1; 2; 3; 4; 5], [6; 7; 8; 9; 10])
let split lst = 
   let rec helper lst l1 l2 =
      match lst with
      | [] -> l1, l2 // return accumulated lists
      | x::xs -> helper xs l2 (x::l1) // prepend x to list 1 and swap lists
helper lst [] []