module Array:sig
..end
数组操作。
此模块的带标签版本可以按照 StdLabels
模块中的描述使用。
type'a
t ='a array
数组类型的别名。
val length : 'a array -> int
返回给定数组的长度(元素数量)。
val get : 'a array -> int -> 'a
get a n
返回数组 a
中的第 n
个元素。第一个元素的编号为 0。最后一个元素的编号为 length a - 1
。您也可以写 a.(n)
代替 get a n
。
Invalid_argument
如果 n
超出范围 0 到 (length a - 1)
。val set : 'a array -> int -> 'a -> unit
set a n x
在原地修改数组 a
,用 x
替换第 n
个元素。您也可以写 a.(n) <- x
代替 set a n x
。
Invalid_argument
如果 n
超出范围 0 到 length a - 1
。val make : int -> 'a -> 'a array
make n x
返回一个长度为 n
的新数组,用 x
初始化。此新数组的所有元素最初在物理上等于 x
(在 ==
谓词的意义上)。因此,如果 x
是可变的,则它在数组的所有元素之间共享,并且通过其中一个数组条目修改 x
将同时修改所有其他条目。
Invalid_argument
如果 n < 0
或 n > Sys.max_array_length
。如果 x
的值为浮点数,则最大大小仅为 Sys.max_array_length / 2
。val create_float : int -> float array
create_float n
返回一个长度为 n
的新的浮点数组,其中包含未初始化的数据。
val init : int -> (int -> 'a) -> 'a array
init n f
返回一个长度为 n
的新数组,其中第 i
个元素初始化为 f i
的结果。换句话说,init n f
将 f
依次应用于整数 0
到 n-1
的结果制成表格。
Invalid_argument
如果 n < 0
或 n > Sys.max_array_length
。如果 f
的返回类型为 float
,则最大大小仅为 Sys.max_array_length / 2
。val make_matrix : int -> int -> 'a -> 'a array array
make_matrix dimx dimy e
返回一个二维数组(数组的数组),第一维为 dimx
,第二维为 dimy
。此新矩阵的所有元素最初在物理上等于 e
。矩阵 m
中的元素 (x,y
) 使用符号 m.(x).(y)
访问。
Invalid_argument
如果 dimx
或 dimy
为负数或大于 Sys.max_array_length
。如果 e
的值为浮点数,则最大大小仅为 Sys.max_array_length / 2
。val init_matrix : int -> int -> (int -> int -> 'a) -> 'a array array
init_matrix dimx dimy f
返回一个二维数组(数组的数组),第一维为 dimx
,第二维为 dimy
,其中索引 (x,y
) 处的元素用 f x y
初始化。矩阵 m
中的元素 (x,y
) 使用符号 m.(x).(y)
访问。
Invalid_argument
如果 dimx
或 dimy
为负数或大于 Sys.max_array_length
。如果 f
的返回类型为 float
,则最大大小仅为 Sys.max_array_length / 2
。val append : 'a array -> 'a array -> 'a array
append v1 v2
返回一个新的数组,其中包含数组 v1
和 v2
的连接。
Invalid_argument
如果 length v1 + length v2 > Sys.max_array_length
。val concat : 'a array list -> 'a array
与 Array.append
相同,但连接的是数组列表。
val sub : 'a array -> int -> int -> 'a array
sub a pos len
返回一个长度为 len
的新数组,其中包含数组 a
中的第 pos
到 pos + len - 1
个元素。
Invalid_argument
如果 pos
和 len
未指定 a
的有效子数组;也就是说,如果 pos < 0
,或 len < 0
,或 pos + len > length a
。val copy : 'a array -> 'a array
copy a
返回 a
的副本,即包含与 a
相同元素的新数组。
val fill : 'a array -> int -> int -> 'a -> unit
fill a pos len x
在原地修改数组 a
,将 x
存储在第 pos
到 pos + len - 1
个元素中。
Invalid_argument
如果 pos
和 len
未指定 a
的有效子数组。val blit : 'a array -> int -> 'a array -> int -> int -> unit
blit src src_pos dst dst_pos len
将数组 src
中从第 src_pos
个元素开始的 len
个元素复制到数组 dst
中,从第 dst_pos
个元素开始。即使 src
和 dst
是同一个数组,并且源块和目标块重叠,它也能正常工作。
Invalid_argument
如果 src_pos
和 len
未指定 src
的有效子数组,或者如果 dst_pos
和 len
未指定 dst
的有效子数组。val to_list : 'a array -> 'a list
to_list a
返回 a
中所有元素的列表。
val of_list : 'a list -> 'a array
of_list l
返回一个新的数组,其中包含 l
中的元素。
Invalid_argument
如果 l
的长度大于 Sys.max_array_length
。val iter : ('a -> unit) -> 'a array -> unit
iter f a
依次将函数 f
应用于 a
中的所有元素。它等效于 f a.(0); f a.(1); ...; f a.(length a - 1); ()
。
val iteri : (int -> 'a -> unit) -> 'a array -> unit
与 Array.iter
相同,但函数应用于元素的索引作为第一个参数,元素本身作为第二个参数。
val map : ('a -> 'b) -> 'a array -> 'b array
map f a
将函数 f
应用于 a
中的所有元素,并使用 f
返回的结果构建一个数组:[| f a.(0); f a.(1); ...; f a.(length a - 1) |]
。
val map_inplace : ('a -> 'a) -> 'a array -> unit
map_inplace f a
将函数 f
应用于 a
中的所有元素,并在原地更新其值。
val mapi : (int -> 'a -> 'b) -> 'a array -> 'b array
与 Array.map
相同,但函数应用于元素的索引作为第一个参数,元素本身作为第二个参数。
val mapi_inplace : (int -> 'a -> 'a) -> 'a array -> unit
与 Array.map_inplace
相同,但函数应用于元素的索引作为第一个参数,元素本身作为第二个参数。
val fold_left : ('acc -> 'a -> 'acc) -> 'acc -> 'a array -> 'acc
fold_left f init a
计算 f (... (f (f init a.(0)) a.(1)) ...) a.(n-1)
,其中 n
是数组 a
的长度。
val fold_left_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a array -> 'acc * 'b array
fold_left_map
是 Array.fold_left
和 Array.map
的组合,它通过对 f
的调用传递一个累加器。
val fold_right : ('a -> 'acc -> 'acc) -> 'a array -> 'acc -> 'acc
fold_right f a init
计算 f a.(0) (f a.(1) ( ... (f a.(n-1) init) ...))
,其中 n
是数组 a
的长度。
val iter2 : ('a -> 'b -> unit) -> 'a array -> 'b array -> unit
iter2 f a b
将函数 f
应用于 a
和 b
中的所有元素。
Invalid_argument
如果数组的大小不同。val map2 : ('a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array
map2 f a b
将函数 f
应用于 a
和 b
中的所有元素,并使用 f
返回的结果构建一个数组:[| f a.(0) b.(0); ...; f a.(length a - 1) b.(length b - 1)|]
。
Invalid_argument
如果数组的大小不同。val for_all : ('a -> bool) -> 'a array -> bool
for_all f [|a1; ...; an|]
检查数组的所有元素是否都满足谓词 f
。也就是说,它返回 (f a1) && (f a2) && ... && (f an)
。
val exists : ('a -> bool) -> 'a array -> bool
exists f [|a1; ...; an|]
检查数组中是否至少有一个元素满足谓词 f
。也就是说,它返回 (f a1) || (f a2) || ... || (f an)
。
val for_all2 : ('a -> 'b -> bool) -> 'a array -> 'b array -> bool
与 Array.for_all
相同,但用于具有两个参数的谓词。
Invalid_argument
如果两个数组的长度不同。val exists2 : ('a -> 'b -> bool) -> 'a array -> 'b array -> bool
与 Array.exists
相同,但用于具有两个参数的谓词。
Invalid_argument
如果两个数组的长度不同。val mem : 'a -> 'a array -> bool
mem a set
为真当且仅当 a
在结构上等于 set
中的一个元素(即,set
中有一个 x
,使得 compare a x = 0
)。
val memq : 'a -> 'a array -> bool
与 Array.mem
相同,但使用物理等价性而不是结构等价性来比较数组元素。
val find_opt : ('a -> bool) -> 'a array -> 'a option
find_opt f a
返回数组 a
中第一个满足谓词 f
的元素,或者如果数组 a
中没有满足 f
的值,则返回 None
。
val find_index : ('a -> bool) -> 'a array -> int option
find_index f a
返回 Some i
,其中 i
是数组 a
中第一个满足 f x
的元素的索引,如果存在这样的元素。
如果不存在这样的元素,则返回 None
。
val find_map : ('a -> 'b option) -> 'a array -> 'b option
find_map f a
按顺序将 f
应用于 a
的元素,并返回第一个 Some v
形式的结果,或者如果不存在,则返回 None
。
val find_mapi : (int -> 'a -> 'b option) -> 'a array -> 'b option
与 find_map
相同,但谓词应用于元素的索引作为第一个参数(从 0 开始计数),元素本身作为第二个参数。
val split : ('a * 'b) array -> 'a array * 'b array
split [|(a1,b1); ...; (an,bn)|]
是 ([|a1; ...; an|], [|b1; ...; bn|])
。
val combine : 'a array -> 'b array -> ('a * 'b) array
combine [|a1; ...; an|] [|b1; ...; bn|]
为 [|(a1,b1); ...; (an,bn)|]
。如果两个数组长度不同,则引发 Invalid_argument
。
val sort : ('a -> 'a -> int) -> 'a array -> unit
根据比较函数按升序对数组进行排序。比较函数必须在其参数比较相等时返回 0,如果第一个参数更大则返回正整数,如果第一个参数更小则返回负整数(有关完整规范,请参见下文)。例如,compare
是一个合适的比较函数。调用 sort
后,数组将在原地按升序排序。 sort
保证在常数堆空间和(最多)对数堆栈空间内运行。
当前实现使用堆排序。它在恒定的堆栈空间中运行。
比较函数规范:令 a
为数组,cmp
为比较函数。以下对于所有 x
、y
、z
在 a
中必须为真
cmp x y
> 0 当且仅当 cmp y x
< 0cmp x y
>= 0 且 cmp y z
>= 0 则 cmp x z
>= 0当 sort
返回时,a
包含与之前相同的元素,以这样的方式重新排序:对于所有 i 和 j 都是 a
的有效索引
cmp a.(i) a.(j)
>= 0 当且仅当 i >= jval stable_sort : ('a -> 'a -> int) -> 'a array -> unit
与 Array.sort
相同,但排序算法是稳定的(即比较相等的元素保持其原始顺序)并且不保证在恒定的堆空间内运行。
当前实现使用归并排序。它使用长度为 n/2
的临时数组,其中 n
是数组的长度。它通常比 Array.sort
的当前实现快。
val fast_sort : ('a -> 'a -> int) -> 'a array -> unit
与 Array.sort
或 Array.stable_sort
相同,在典型输入上速度更快者优先。
val shuffle : rand:(int -> int) -> 'a array -> unit
shuffle rand a
使用 rand
随机排列 a
的元素以获得随机性。排列的分布是均匀的。
rand
必须使得对 rand n
的调用返回范围 [0
;n-1
] 内的均匀分布随机数。 Random.int
可用于此(不要忘记 初始化 生成器)。
val to_seq : 'a array -> 'a Seq.t
按升序遍历数组。在迭代期间对数组的修改将反映在序列中。
val to_seqi : 'a array -> (int * 'a) Seq.t
按升序遍历数组,生成索引和元素。在迭代期间对数组的修改将反映在序列中。
val of_seq : 'a Seq.t -> 'a array
从生成器创建数组
从多个域并发访问数组时,必须谨慎:访问数组永远不会导致程序崩溃,但未同步的访问可能会产生令人惊讶的(非顺序一致的)结果。
访问多个数组元素的每个数组操作都不是原子的。这包括迭代、扫描、排序、拆分和合并数组。
例如,考虑以下程序
let size = 100_000_000
let a = Array.make size 1
let d1 = Domain.spawn (fun () ->
Array.iteri (fun i x -> a.(i) <- x + 1) a
)
let d2 = Domain.spawn (fun () ->
Array.iteri (fun i x -> a.(i) <- 2 * x + 1) a
)
let () = Domain.join d1; Domain.join d2
执行完此代码后,数组 a
的每个字段都将是 2
、3
、4
或 5
。如果需要原子性,则用户必须实现他们自己的同步(例如,使用 Mutex.t
)。
如果两个域仅访问数组的不同部分,则观察到的行为等同于来自两个域的操作的某种顺序交错。
当两个域在没有同步的情况下访问同一个数组元素,并且至少其中一个访问是写操作时,就会发生数据竞争。在没有数据竞争的情况下,观察到的行为等同于来自不同域的操作的某种顺序交错。
只要可能,应通过使用同步来协调对数组元素的访问来避免数据竞争。
事实上,在存在数据竞争的情况下,程序不会崩溃,但观察到的行为可能不等于来自不同域的操作的任何顺序交错。尽管如此,即使在存在数据竞争的情况下,读取操作也会返回先前对该位置的一些写入的值(对浮点数组有一些例外)。
浮点数组在存在数据竞争的情况下有两个补充警告。
首先,blit 操作可能逐字节复制数组。此类 blit 操作与其他操作之间的数据竞争可能会产生令人惊讶的值,因为撕裂:部分写入与其他操作交错会导致浮点值,这些值在顺序执行时不会出现。
例如,在结束时
let zeros = Array.make size 0.
let max_floats = Array.make size Float.max_float
let res = Array.copy zeros
let d1 = Domain.spawn (fun () -> Array.blit zeros 0 res 0 size)
let d2 = Domain.spawn (fun () -> Array.blit max_floats 0 res 0 size)
let () = Domain.join d1; Domain.join d2
res
数组可能包含既不是 0.
也不是 max_float
的值。
其次,在 32 位架构上,获取或设置字段涉及两个独立的内存访问。在存在数据竞争的情况下,用户可能会观察到对任何操作的撕裂。