mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-06 11:15:31 -05:00
Make Seq.to_array only traverse seq once
This PR suggests a change to `Seq.to_array`, which uses construction of an intermediate list to prevent traversing the Seq twice. This requires the allocation of an intermediate list, but it eliminates the surprising behavior that otherwise occurs with state-full sequences, due to the extra traversal required to obtain the length of the sequence. E.g., with the previous implementation, the value of `to_array` for the sequence constructed in the test added in this commit is `[|4;5;6|]`, while `to_list` gives `[|1;2;3|]`.
This commit is contained in:
parent
74954f53a0
commit
4104ce3fd7
2 changed files with 16 additions and 9 deletions
|
|
@ -395,14 +395,18 @@ let of_array a =
|
||||||
aux a 0
|
aux a 0
|
||||||
|
|
||||||
let to_array l =
|
let to_array l =
|
||||||
match l() with
|
(* We contruct the length and list of seq elements (in reverse) in one pass *)
|
||||||
| Nil -> [| |]
|
let len, ls = fold_left (fun (i, acc) x -> (i + 1, x :: acc)) (0, []) l in
|
||||||
| Cons (x, _) ->
|
(* The length is used to initialize the array, and then to derive the index for
|
||||||
let n = length l in
|
each item, working back from the last. This lets us only traverse the list
|
||||||
let a = Array.make n x in (* need first elem to create [a] *)
|
twice, instead of having to reverse it. *)
|
||||||
iteri
|
match ls with
|
||||||
(fun i x -> a.(i) <- x)
|
| [] -> [||]
|
||||||
l;
|
| init::rest ->
|
||||||
|
let a = Array.make len init in
|
||||||
|
(* Subtract 1 for len->index conversion and 1 for the removed [init] *)
|
||||||
|
let idx = len - 2 in
|
||||||
|
ignore (List.fold_left (fun i x -> a.(i) <- x; i - 1) idx rest);
|
||||||
a
|
a
|
||||||
|
|
||||||
(*$Q
|
(*$Q
|
||||||
|
|
@ -412,6 +416,9 @@ let to_array l =
|
||||||
(*$T
|
(*$T
|
||||||
of_array [| 1; 2; 3 |] |> to_list = [1;2;3]
|
of_array [| 1; 2; 3 |] |> to_list = [1;2;3]
|
||||||
of_list [1;2;3] |> to_array = [| 1; 2; 3; |]
|
of_list [1;2;3] |> to_array = [| 1; 2; 3; |]
|
||||||
|
let r = ref 1 in \
|
||||||
|
let s = unfold (fun i -> if i < 3 then let x = !r in incr r; Some (x, succ i) else None) 0 in \
|
||||||
|
to_array s = [| 1; 2; 3; |]
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let rec to_iter res k = match res () with
|
let rec to_iter res k = match res () with
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,7 @@ val of_array : 'a array -> 'a t
|
||||||
@since 0.13 *)
|
@since 0.13 *)
|
||||||
|
|
||||||
val to_array : 'a t -> 'a array
|
val to_array : 'a t -> 'a array
|
||||||
(** Convert into array. Iterate twice.
|
(** Convert into array.
|
||||||
@since 0.13 *)
|
@since 0.13 *)
|
||||||
|
|
||||||
val to_rev_list : 'a t -> 'a list
|
val to_rev_list : 'a t -> 'a list
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue