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

时间:2011-10-30 00:46:34

标签: 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 -> splitEven tail (list1::head) list2
    and splitEven oList list1 list2 =
        match oList with
        | [] -> []
        | head :: tail -> splitOdd tail list1 (list2::head)
    splitOdd list [] []

8 个答案:

答案 0 :(得分:39)

没有堆栈溢出的实现:

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

答案 1 :(得分:11)

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

let rec splitList = function
    | [] -> [], []
    | [x]-> [x], []
    | x1::x2::xs -> let xs1, xs2 = splitList xs
                    x1::xs1, x2::xs2

答案 2 :(得分:6)

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

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

应用于您的样本,它可以产生您想要的结果:

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

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

答案 3 :(得分:2)

另一个(效率较低)选项

let splitList xs = 
    let odd, even =
        xs
        |> List.zip [ 1 .. (List.length xs) ]
        |> List.partition (fun (i, _) -> i % 2 <> 0)
    [ odd |> List.map snd; even |> List.map snd ]

如果您想避免创建临时列表,请考虑使用序列:

let splitListSeq xs =
    xs
    |> Seq.mapi (fun i x -> (i % 2 = 0, x))
    |> Seq.groupBy (fun (b, _) -> b)
    |> Seq.map snd
    |> Seq.map ((Seq.map snd) >> Seq.toList)
    |> Seq.toList

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

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

答案 4 :(得分:2)

看起来这就是你想要的,这确实是一种很好的方式,因为它是尾递归的。

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

答案 5 :(得分:1)

听起来你想要List.partition&lt;'T&gt; (http://msdn.microsoft.com/en-us/library/ee353782.aspx)。此函数接受谓词和列表,并返回一对(2元组),其中第一个元素是通过测试的所有元素,第二个元素是未通过测试的所有元素。因此,您可以使用以下方法对赔率和赔率进行分类:

List.partition odd [1;2;4;6;7;9]

如果您真的想要一个列表,可以使用fstsnd从元组中提取元素并将它们放在列表中。

祝你好运!

答案 6 :(得分:1)

我的2¢,在OCaml中,因为仍有赏金开放。

也许你可以给我们一个暗示你想要的东西。优雅? FP?尾递归?性能

修改

我删除了较长的解决方案。要使List.partition工作,谓词就丢失了。 这是:

let so_split lst = 
  let flag = ref false in
  List.partition (fun e -> flag := not !flag; !flag) lst

改进了吗?测试解决方案:

# so_split [1;2;4;6;7;9];;
- : int list * int list = ([1; 4; 7], [2; 6; 9])

答案 7 :(得分:0)

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

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