OCaml - 从一维数组到二维数组的转换
OCaml - Conversion from one-dimensional array to two-dimensional array
我正在尝试在 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
;;
我做错了什么?
您错误地创建了二维数组。 Array.make
只会复制第二个参数 dim
次。所以,你有一个包含三个指向同一个数组的指针的数组。查看 以了解有关如何正确烘焙数组的更多详细信息。使用 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页)。
详细说明@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|]|]
你的代码错误的地方是
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
tests for physical equality of e1
and e2
. On mutable types such as references, arrays, byte sequences, records with mutable fields and objects with mutable instance variables, e1 == e2
is true if and only if physical modification of e1
also affects e2
. On non-mutable types, the behavior of ( == )
is implementation-dependent; however, it is guaranteed that e1 == e2
implies compare e1 e2 = 0
.
我们可以认为这是一种正式的方式,可以说这两个结构“真的一样”。
如果您想修改代码的结构,可以利用 Array.make_matrix
函数,它会生成一个新的二维数组。如果您厌倦了调试 for 循环中的错误,您可以使用更像 ocaml 的解决方案:
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
另请参阅
- What's the difference between "equal (=)" and "identical (==)" in ocaml?
- Does != have meaning in OCaml?
我正在尝试在 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
;;
我做错了什么?
您错误地创建了二维数组。 Array.make
只会复制第二个参数 dim
次。所以,你有一个包含三个指向同一个数组的指针的数组。查看 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页)。
详细说明@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|]|]
你的代码错误的地方是
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
tests for physical equality ofe1
ande2
. On mutable types such as references, arrays, byte sequences, records with mutable fields and objects with mutable instance variables,e1 == e2
is true if and only if physical modification ofe1
also affectse2
. On non-mutable types, the behavior of( == )
is implementation-dependent; however, it is guaranteed thate1 == e2
implies comparee1 e2 = 0
.
我们可以认为这是一种正式的方式,可以说这两个结构“真的一样”。
如果您想修改代码的结构,可以利用 Array.make_matrix
函数,它会生成一个新的二维数组。如果您厌倦了调试 for 循环中的错误,您可以使用更像 ocaml 的解决方案:
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
另请参阅
- What's the difference between "equal (=)" and "identical (==)" in ocaml?
- Does != have meaning in OCaml?