OCaml压缩元素的数组2乘2

时间:2016-10-27 18:41:43

标签: ocaml

我需要检查数组是否在OCaml中正确排序。

因此,我正在考虑将字符2分组2,然后进行折叠操作,我将其进行比较。

但是,我不知道如何将它们分组。

在Scala中,它看起来像这样:

val k = Array(1, 2, 3, 4)
k.zip(k.tail)

知道在OCaml中看起来会怎样?

2 个答案:

答案 0 :(得分:3)

使用Array.init函数创建一个新数组并用它们填充它,例如..

let zip xs ys = Array.init (Array.length xs) (fun i -> x.(i),y.(i))

但是,我不推荐这种方法。如果您可以使用递归函数轻松表达算法,则没有理由创建中间数据结构。

如果您需要将数组xs与数组ys进行比较,那么您只需执行xs = ys

看起来,您还希望不创建两个数组的zip,但是从数组中提取连续元素对,这里可以使用Array.init来完成:

let zip_with_tail xs = match Array.length xs with
  | 0 | 1 -> [| |]
  | n -> Array.init (n-1) (fun i -> xs.(i),xs.(i+1))

将它与不使用中间数据结构的is_sorted函数进行比较:

  

let is_sorted xs = let rec ordered i = i = 0 || xs.(i-1) <= xs.(i) && ordered (i-1) in match Array.length xs with | 0 | 1 -> true | n -> ordered (n-1)

样式装饰/进程/ undecorate在懒惰序列中运行良好,在编译器中具有良好的森林砍伐能力。例如在Haskell中。或者在已经很慢的语言中,没有必要打扰。 我不确定Scala,他们的数组是否是懒惰的。在任何情况下,OCaml数组都是具体的数据结构,OCaml编译器不会优化它(并且不应该 - 数组的语义不允许这样做)。但是,这种编程风格仍然适用于OCaml。您可以使用Core库,它提供一个名为Sequence的惰性容器。您可以使用它以相同的方式轻松定义zip_with_tail,如在Scala中:

 let zip_with_tail xs = Sequence.(zip xs (drop xs 1))

以下是一个例子:

# let xs = Sequence.of_list [1;2;3;4;5;6];;
val xs : int Core_kernel.Std.Sequence.t = {1, 2, 3, 4, 5, 6}
# zip_with_tail xs;;
- : (int * int) Core_kernel.Std.Sequence.t =
{(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)}

因此,您可以很好地定义is_sorted

let is_sorted xs = zip_with_tail xs |>
                   Sequence.for_all ~f:(fun (x,y) -> x <= y)

这里zip_with_tail xs不会创建一个中间数组,它实际上有O(1)的复杂性。在引擎盖下面它将返回一个函数,它将生成元素。 Sequence.for_all将检查它们是否全部排序。

答案 1 :(得分:2)

这将使数组成为一对相邻元素的列表:

let a2pairs a =
    let mkpr x (prevo, prs) =
        match prevo with
        | None -> (Some x, [])
        | Some y -> (Some x, (x, y) :: prs)
    in
    snd (Array.fold_right mkpr a (None, []))

它的工作原理如下:

# a2pairs [| 1;2;3;4 |];;
- : (int * int) list = [(1, 2); (2, 3); (3, 4)]

但我同意@ivg认为创建这个中间数据结构可能不值得。您可以使用几乎相同的函数来比较相邻元素,并累积一个布尔值,表明它们是否都是正确的顺序。