无法在ocaml中正确排序列表

时间:2017-09-25 05:09:39

标签: sorting ocaml

所以我试图对这个整数列表进行排序,以便所有偶数都在前面,而赔率都在后面。我现在有我的程序,它在很大程度上起作用,但它一直在颠倒我不想要它做的赔率数字的顺序。例如。给出输入[1; 2; 3; 4; 5; 6]我想得到[2; 4; 6; 1; 3; 5],但我得到[2; 4; 6; 5] ; 3; 1]非常感谢任何帮助!

let rec evens (xl:int list) (odd:int list) : int list =
   match xl with
      | [] -> []
      | h::t ->
         if h mod 2 = 0
            then (h)::evens t odd
         else
            evens t odd@[(h)]

2 个答案:

答案 0 :(得分:2)

当前代码的主要部分解析如下:

if h mod 2 = 0 then
    h :: (evens t odd)
else
    (evens t odd) @ [h]

它说:如果下一个数字h是偶数,请对列表的其余部分进行排序,然后将h添加到前面。如果下一个数字h为奇数,请对列表的其余部分进行排序,然后将h添加到结尾。因此,奇数将在最后反转。

值得注意的是,名为odd的参数始终保持不变,因此将始终为空列表(或者作为evens的第二个参数传递的任何内容)。

当我第一次看到您的代码时,我假设您计划在odd参数中累积奇数。如果您想这样做,则需要进行两项更改。首先你需要像这样重写:

if h mod 2 = 0 then
    h :: evens t odd
else
    evens t (odd @ [h])

如果要将h添加到odd参数,则OCaml的优先规则需要括号。您当前的代码会将h添加到evens的返回结果中(如上所述)。

此重写将在odd参数中按顺序累积奇数。

然后你需要在递归结束时实际使用奇数参数。即,当xl为空时,您需要使用它。

答案 1 :(得分:2)

标准库为您的问题提供了一个简洁的解决方案。

List.partition (fun x -> x mod 2 = 0) [1;2;3;4;5;6]
- : int list * int list = ([2; 4; 6], [1; 3; 5])

partition函数将您的列表拆分为两个列表的元组:

  1. 验证谓词的元素列表;
  2. 没有的元素列表。
  3. 您所要做的就是将这些列表组合在一起。

    let even_first l =
      let evens, odds = List.partition (fun x -> x mod 2 = 0) l in
      evens @ odds
    

    如果你想让它更通用,那么让谓词成为一个参数:

    let order_by_predicate ~f l =
      let valid, invalid = List.partition f l in
      valid @ invalid