module ArrayLabels: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
,將編號為 n
的元素替換為 x
。您也可以寫 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 -> f:(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 : dimx:int -> dimy: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 : dimx:int -> dimy:int -> f:(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
與 ArrayLabels.append
相同,但串連的是陣列列表。
val sub : 'a array -> pos:int -> len: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 -> pos:int -> len:int -> 'a -> unit
fill a ~pos ~len x
就地修改陣列 a
,將 x
儲存在編號為 pos
到 pos + len - 1
的元素中。
Invalid_argument
,如果 pos
和 len
沒有指定 a
的有效子陣列。val blit : src:'a array -> src_pos:int -> dst:'a array -> dst_pos:int -> len: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 : f:('a -> unit) -> 'a array -> unit
iter ~f a
依次將函式 f
應用於 a
的所有元素。它等效於 f a.(0); f a.(1); ...; f a.(length a - 1); ()
。
val iteri : f:(int -> 'a -> unit) -> 'a array -> unit
與 ArrayLabels.iter
相同,但函式會將元素的索引作為第一個引數,將元素本身作為第二個引數。
val map : f:('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 : f:('a -> 'a) -> 'a array -> unit
map_inplace ~f a
將函式 f
應用於 a
的所有元素,並就地更新它們的值。
val mapi : f:(int -> 'a -> 'b) -> 'a array -> 'b array
與 ArrayLabels.map
相同,但函式會將元素的索引作為第一個引數,將元素本身作為第二個引數。
val mapi_inplace : f:(int -> 'a -> 'a) -> 'a array -> unit
與 ArrayLabels.map_inplace
相同,但函式會將元素的索引作為第一個引數,將元素本身作為第二個引數。
val fold_left : f:('acc -> 'a -> 'acc) -> init:'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 : f:('acc -> 'a -> 'acc * 'b) -> init:'acc -> 'a array -> 'acc * 'b array
fold_left_map
是 ArrayLabels.fold_left
和 ArrayLabels.map
的組合,它會將累加器透過對 f
的呼叫傳遞。
val fold_right : f:('a -> 'acc -> 'acc) -> 'a array -> init:'acc -> 'acc
fold_right ~f a ~init
計算 f a.(0) (f a.(1) ( ... (f a.(n-1) init) ...))
,其中 n
是陣列 a
的長度。
val iter2 : f:('a -> 'b -> unit) -> 'a array -> 'b array -> unit
iter2 ~f a b
將函式 f
應用於 a
和 b
的所有元素。
Invalid_argument
,如果陣列大小不同。val map2 : f:('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 : f:('a -> bool) -> 'a array -> bool
for_all ~f [|a1; ...; an|]
檢查陣列的所有元素是否滿足謂詞 f
。也就是說,它會傳回 (f a1) && (f a2) && ... && (f an)
。
val exists : f:('a -> bool) -> 'a array -> bool
exists ~f [|a1; ...; an|]
檢查陣列中是否至少有一個元素滿足謂詞 f
。也就是說,它會傳回 (f a1) || (f a2) || ... || (f an)
。
val for_all2 : f:('a -> 'b -> bool) -> 'a array -> 'b array -> bool
與 ArrayLabels.for_all
相同,但適用於雙引數謂詞。
Invalid_argument
,如果兩個陣列的長度不同。val exists2 : f:('a -> 'b -> bool) -> 'a array -> 'b array -> bool
與 ArrayLabels.exists
相同,但適用於雙引數謂詞。
Invalid_argument
,如果兩個陣列的長度不同。val mem : 'a -> set:'a array -> bool
mem a ~set
為真,若且唯若 a
在結構上等於 set
的一個元素(即,set
中存在一個 x
,使得 compare a x = 0
)。
val memq : 'a -> set:'a array -> bool
與 ArrayLabels.mem
相同,但使用物理相等性而非結構相等性來比較陣列元素。
val find_opt : f:('a -> bool) -> 'a array -> 'a option
find_opt ~f a
會回傳陣列 a
中第一個符合謂詞 f
的元素,如果陣列 a
中沒有任何值符合 f
,則回傳 None
。
val find_index : f:('a -> bool) -> 'a array -> int option
find_index ~f a
會回傳 Some i
,其中 i
是陣列 a
中第一個符合 f x
的元素的索引值,如果存在這樣的元素。
如果沒有這樣的元素,則回傳 None
。
val find_map : f:('a -> 'b option) -> 'a array -> 'b option
find_map ~f a
會依序將 f
應用於 a
的元素,並回傳第一個形式為 Some v
的結果,如果不存在則回傳 None
。
val find_mapi : f:(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 : cmp:('a -> 'a -> int) -> 'a array -> unit
根據比較函式以遞增順序排序陣列。如果兩個參數相等,比較函式必須回傳 0;如果第一個參數較大,則回傳正整數;如果第一個參數較小,則回傳負整數 (完整規格請參閱下方)。例如,compare
是一個適合的比較函式。呼叫 sort
後,陣列會原地以遞增順序排序。sort
保證以常數堆疊空間和 (最多) 對數堆疊空間執行。
目前的實作使用堆積排序。它以常數堆疊空間執行。
比較函式的規格:設 a
為陣列,而 cmp
為比較函式。對於 a
中的所有 x
、y
、z
,以下必須成立:
cmp y x
< 0 時,cmp x y
> 0cmp x y
>= 0 且 cmp y z
>= 0,則 cmp x z
>= 0當 sort
回傳時,a
會包含與之前相同的元素,但會重新排序,使得對於所有 a
的有效索引值 i 和 j,以下成立:
cmp a.(i) a.(j)
>= 0val stable_sort : cmp:('a -> 'a -> int) -> 'a array -> unit
與 ArrayLabels.sort
相同,但排序演算法是穩定的 (也就是說,比較相等的元素會保持其原始順序),並且不保證以常數堆疊空間執行。
目前的實作使用合併排序。它使用長度為 n/2
的暫存陣列,其中 n
是陣列的長度。它通常比目前的 ArrayLabels.sort
實作更快。
val fast_sort : cmp:('a -> 'a -> int) -> 'a array -> unit
與 ArrayLabels.sort
或 ArrayLabels.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 = ArrayLabels.make size 1
let d1 = Domain.spawn (fun () ->
ArrayLabels.iteri ~f:(fun i x -> a.(i) <- x + 1) a
)
let d2 = Domain.spawn (fun () ->
ArrayLabels.iteri ~f:(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 位元架構上,取得或設定欄位涉及兩個單獨的記憶體存取。在存在資料競爭的情況下,使用者可能會在任何操作中觀察到撕裂。