List 将项目列表拆分为奇数和偶数索引项目的两个列表

List 将项目列表拆分为奇数和偶数索引项目的两个列表,list,f#,functional-programming,ocaml,tail-recursion,List,F#,Functional Programming,Ocaml,Tail Recursion,我想创建一个函数,它接受一个列表并返回两个列表:第一个包含所有奇数项,第二个包含所有偶数项 例如,给定[1;2;4;6;7;9],我想返回[[1;4;7];[2;6;9] 到目前为止,我已经写了这篇文章,我不知道如何进步 let splitList list = let rec splitOdd oList list1 list2 = match oList with | [] -> [] | head :: tail -> s

我想创建一个函数,它接受一个列表并返回两个列表:第一个包含所有奇数项,第二个包含所有偶数项

例如,给定
[1;2;4;6;7;9]
,我想返回
[[1;4;7];[2;6;9]

到目前为止,我已经写了这篇文章,我不知道如何进步

let splitList list =
    let rec splitOdd oList list1 list2 =
        match oList with
        | [] -> []
        | head :: tail -> splitEven tail (list1::head) list2
    and splitEven oList list1 list2 =
        match oList with
        | [] -> []
        | head :: tail -> splitOdd tail list1 (list2::head)
    splitOdd list [] []

如果您指的是项目位置的奇数和偶数值,这里有一个(非尾部递归)解决方案:

let rec splitList = function
    | [] -> [], []
    | [x]-> [x], []
    | x1::x2::xs -> let xs1, xs2 = splitList xs
                    x1::xs1, x2::xs2
let splitList ll =
    ll
    |> List.mapi (fun i x -> (i % 2 = 0, x))
    |> List.partition fst
    |> fun (odd,even) -> [List.map snd odd, List.map snd even];;

val splitList : 'a list -> 'a list list
# so_split [1;2;4;6;7;9];;
- : int list * int list = ([1; 4; 7], [2; 6; 9])
let splitList (list:int list) =
    let odds = [for i in 0..list.Length-1 do
                  if i%2=1 then
                    yield list.[i]]
    let evens = [for i in 0..list.Length-1 do
                    if i%2=0 then
                        yield list.[i]]
    odds,evens 

听起来你想要List.partition另一个(效率较低的)选项

然而,另一个类似于丹尼尔的版本:

let splitListRec xs =
    let rec loop l r = function
        | []      -> [l; r]
        | x::[]   -> [x::l; r]
        | x::y::t -> loop (x::l) (y::r) t
    loop [] [] xs |> List.map List.rev

看起来这就是你想要的,这确实是一个很好的方法,因为它是尾部递归的

let splitList items =
  let rec splitOdd odds evens = function
    | [] -> odds, evens
    | h::t -> splitEven (h::odds) evens t
  and splitEven odds evens = function
    | [] -> odds, evens
    | h::t -> splitOdd odds (h::evens) t
  let odds, evens = splitOdd [] [] items
  List.rev odds, List.rev evens

下面是一个简单的非递归解决方案:

let rec splitList = function
    | [] -> [], []
    | [x]-> [x], []
    | x1::x2::xs -> let xs1, xs2 = splitList xs
                    x1::xs1, x2::xs2
let splitList ll =
    ll
    |> List.mapi (fun i x -> (i % 2 = 0, x))
    |> List.partition fst
    |> fun (odd,even) -> [List.map snd odd, List.map snd even];;

val splitList : 'a list -> 'a list list
# so_split [1;2;4;6;7;9];;
- : int list * int list = ([1; 4; 7], [2; 6; 9])
let splitList (list:int list) =
    let odds = [for i in 0..list.Length-1 do
                  if i%2=1 then
                    yield list.[i]]
    let evens = [for i in 0..list.Length-1 do
                    if i%2=0 then
                        yield list.[i]]
    odds,evens 
将其应用于您的样本,可以得到您想要的结果:

splitList [1;2;4;6;7;9];;

val it : int list list = [[1; 4; 7]; [2; 6; 9]]

不堆栈溢出的实现:

let splitList list = List.foldBack (fun x (l,r) -> x::r, l) list ([],[])

我的2美分,在OCaml,因为还有悬赏

也许你可以给我们一个暗示你想要什么。优雅?FP?尾部递归?表演

编辑:

我删除了较长的解决方案。为使List.partition正常工作,缺少谓词。 这是:

let so_split lst = 
  let flag = ref false in
  List.partition (fun e -> flag := not !flag; !flag) lst
有什么改进吗?测试解决方案:

let rec splitList = function
    | [] -> [], []
    | [x]-> [x], []
    | x1::x2::xs -> let xs1, xs2 = splitList xs
                    x1::xs1, x2::xs2
let splitList ll =
    ll
    |> List.mapi (fun i x -> (i % 2 = 0, x))
    |> List.partition fst
    |> fun (odd,even) -> [List.map snd odd, List.map snd even];;

val splitList : 'a list -> 'a list list
# so_split [1;2;4;6;7;9];;
- : int list * int list = ([1; 4; 7], [2; 6; 9])
let splitList (list:int list) =
    let odds = [for i in 0..list.Length-1 do
                  if i%2=1 then
                    yield list.[i]]
    let evens = [for i in 0..list.Length-1 do
                    if i%2=0 then
                        yield list.[i]]
    odds,evens 

为了完整起见,这里有一个无聊的、更迫切的解决方案:

let rec splitList = function
    | [] -> [], []
    | [x]-> [x], []
    | x1::x2::xs -> let xs1, xs2 = splitList xs
                    x1::xs1, x2::xs2
let splitList ll =
    ll
    |> List.mapi (fun i x -> (i % 2 = 0, x))
    |> List.partition fst
    |> fun (odd,even) -> [List.map snd odd, List.map snd even];;

val splitList : 'a list -> 'a list list
# so_split [1;2;4;6;7;9];;
- : int list * int list = ([1; 4; 7], [2; 6; 9])
let splitList (list:int list) =
    let odds = [for i in 0..list.Length-1 do
                  if i%2=1 then
                    yield list.[i]]
    let evens = [for i in 0..list.Length-1 do
                    if i%2=0 then
                        yield list.[i]]
    odds,evens 

不能使用List.partition吗?@Mathias:No,
List.partition
使用谓词,在这种情况下没有合适的谓词。同样,问题是关于奇偶索引
partition
不会将索引传递给用于分区的函数。我尝试了如下方法:List.partition(fun I->(I%2=0))[1;2;4;6;7;9],得到了这个结果([2;4;6],[1;7;9])。所以,这个解决方案非常善于区分奇数和偶数。完全是我想要的。。。谢谢!这门语言肯定有很多东西要学,尤其是它的简洁性。不过,这种实现的问题是,它不是尾部递归的,它会在大约80000个元素的列表上导致堆栈溢出。F#实现者应该注意到,
foldBack
将列表转换为数组,以允许尾部到头部的遍历。这通常是一件好事,因为数组遍历速度很快,但是对于较大的列表,应该考虑成本。该死,这是一个非常好的解决方案。我花了几秒钟才意识到它是如何工作的,但我不得不承认这个解决方案非常优雅(y)。那么,你能更详细地解释一下它是如何工作的吗?如果我理解正确,List.foldBack将函数应用于列表中的每个元素,从尾部到头部?([],[])是存储状态的元组。有趣的部分是如何工作的?x::r的含义是什么?Thanks@D根据折叠的定义,在伪代码中,
split[a;b;c;d]-->(a::r,l){where(l,r)([],[])
。因此,
[]-->([],[])
[d]([d])
[c;d]([c],[d])
[b;c;d],[b;d],[c])
[a;b;b;[b];[c];[c],[b],[b],[b],[c],[b],[c],[b],[b],[c],[b],[c],[b],[c],[c],]“一个或多个答案堪称典范,值得额外赏金。“:)这既是为了奖励答案,也是为了吸引人们对这个问题的注意,这样更多的人可能会对它感兴趣。好吧,我对它感兴趣。当有人问更多的信息时,你通常不会重复已知的文本,而是对其进行解释,或者更好……列表理解是否定义了延迟生成的序列,用F#表示?你需要使用'seq'{}对于懒惰的东西,但看起来sameI只是想知道这需要对列表进行两次传递,还是可以将它编译成一个(懒惰的)传递,在传递过程中添加到一个或另一个结果序列的尾部。(我非常喜欢)。列表理解只会产生一个列表(或seq)。