我试图将一维数组转换为OCaml中的二维数组。
在测试我写的函数时:
# to_array2d [|1;2;3;1;2;4;1;2;5|];;
我得到的结果不正确:
int array array = [|[|1; 2; 5|]; [|1; 2; 5|]; [|1; 2; 5|]|]
正确的结果应该是:
int array array = [|[|1; 2; 3|]; [|1; 2; 4|]; [|1; 2; 5|]|]
以下是代码:
let to_array2d (array1d: int array) : int array array =
let dim = int_of_float (sqrt (float (Array.length array1d))) in
let array2d = Array.make dim (Array.make dim 0 ) in
for i = 0 to (dim - 1) do
for j = 0 to (dim - 1) do
array2d.(i).(j) <- (Array.get array1d (i * dim + j))
done
done;
array2d
;;
我做错了什么?
答案 0 :(得分:3)
代码中的错误位置是
let b =
Array.make dim (Array.make dim 0)
这不是你想要的。名称b
不在您的代码中,但便于讨论。为了理解你看到的内容,让我们以下面的等效方式重写这段代码:
let b =
let a = Array.make dim 0 in
Array.make dim a
此代码生成一个长度为dim
的数组,其条目均为a
。这些不是a
的副本,它们只是a
,具有不同的名称。在OCaml中表达这种结构的正确方法是说这些结构在物理上相等并且==
运算符测试物理相等。
# b.(0) == b.(1);;
true
物理平等是一种更强大的关系,而不是由更常见的=
运算符测试的结构平等。指定给定两个物理上相同的可变结构,如b.(0)
和b.(1)
,其中任何一个的修改也会影响另一个,或documentation of the Pervasives module的话:
val (==) : 'a -> 'a -> bool
e1 == e2
测试e1
和e2
的物理平等。在可变类型(如引用,数组,字节序列,具有可变字段的记录和具有可变实例变量的对象)上,当{且仅e1 == e2
的物理修改也影响e1
时,e2
为真。在非可变类型上,( == )
的行为依赖于实现;但是,保证e1 == e2
暗示比较e1 e2 = 0
。
我们可以认为这是一种正式的方式来说这两种结构“真的是一样的”。
如果你想要代码的结构,你可以利用Array.make_matrix
函数生成一个新的二维数组。如果您厌倦了在for循环中调试错误,可以使用更多的ocaml-ish解决方案:
let unpack dim a =
let line i =
Array.init dim (fun j -> a.(i*dim + j))
in
Array.init dim line
let to_array2d a =
let dim = int_of_float (sqrt (float (Array.length array1d))) in
unpack dim a
另见
答案 1 :(得分:2)
您错误地创建了2D数组。 Array.make
只会复制第二个参数dim
次。所以,你有一个指向同一个数组的三个指针的数组。查看here以获取有关如何正确烹饪阵列的更多详细信息。使用Array.init
函数
let to_array2d (array1d: int array) : int array array =
let dim = int_of_float (sqrt (float (Array.length array1d))) in
Array.init dim (fun i -> Array.init dim (fun j -> array1d.(i * dim + j)))
虽然,我不喜欢sqrt
长度的想法。
OCaml Book可以找到关于这个问题的非常好的解释。请参阅第68页(pdf的第94页)。
答案 2 :(得分:2)
详细说明@ ivg的答案:Array.make
将获取您给出的值并将其放入新数组的所有元素中。对于具有结构的值(如数组),这意味着您将最终出现三次相同的值。
# let a = Array.make 3 (Array.make 4 0);;
val a : int array array = [|[|0; 0; 0; 0|]; [|0; 0; 0; 0|]; [|0; 0; 0; 0|]|]
# a.(1).(3) <- 17;;
- : unit = ()
# a;;
- : int array array = [|[|0; 0; 0; 17|]; [|0; 0; 0; 17|]; [|0; 0; 0; 17|]|]
#
您不希望出现相同的数组。你每次都想要一个不同的数组。为此,您可以使用Array.init
(比如说)。
# let a = Array.init 3 (fun _ -> Array.make 4 0);;
val a : int array array = [|[|0; 0; 0; 0|]; [|0; 0; 0; 0|]; [|0; 0; 0; 0|]|]
# a.(1).(3) <- 17;;
- : unit = ()
# a;;
- : int array array = [|[|0; 0; 0; 0|]; [|0; 0; 0; 17|]; [|0; 0; 0; 0|]|]