From d135f73c7656de3a0453214c424da616a3a33dc6 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 9 Mar 2017 21:41:38 +0100 Subject: [PATCH] add `CCArray.{fold_map,scan_left}` (close #101) --- src/core/CCArray.ml | 42 ++++++++++++++++++++++++++++++++++++++++++ src/core/CCArray.mli | 11 +++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/core/CCArray.ml b/src/core/CCArray.ml index 85e152c8..8785019c 100644 --- a/src/core/CCArray.ml +++ b/src/core/CCArray.ml @@ -71,6 +71,48 @@ let fold_while f acc a = fold_while (fun acc b -> if b then acc+1, `Continue else acc, `Stop) 0 (Array.of_list [true;true;false;true]) = 2 *) +let fold_map f acc a = + let n = length a in + (* need special case for initializing the result *) + if n = 0 then acc, [||] + else ( + let acc, b0 = f acc a.(0) in + let res = Array.make n b0 in + let acc = ref acc in + for i = 1 to n-1 do + let new_acc, b = f !acc a.(i) in + acc := new_acc; + res.(i) <- b; + done; + !acc, res + ) + +(*$= + (6, [|"1"; "2"; "3"|]) \ + (fold_map (fun acc x->acc+x, string_of_int x) 0 [|1;2;3|]) +*) + +(*$Q + Q.(array int) (fun a -> \ + fold_map (fun acc x -> x::acc, x) [] a = (List.rev @@ Array.to_list a, a)) +*) + +let scan_left f acc a = + let n = length a in + let res = Array.make (n+1) acc in + Array.iteri + (fun i x -> + let new_acc = f res.(i) x in + res.(i+1) <- new_acc) + a; + res + +(*$= & ~printer:Q.Print.(array int) + [|0;1;3;6|] (scan_left (+) 0 [|1;2;3|]) + [|0|] (scan_left (+) 0 [||]) +*) + + let iter = Array.iter let iteri = Array.iteri diff --git a/src/core/CCArray.mli b/src/core/CCArray.mli index 611d7b9f..42ad6925 100644 --- a/src/core/CCArray.mli +++ b/src/core/CCArray.mli @@ -41,6 +41,17 @@ val fold_while : ('a -> 'b -> 'a * [`Stop | `Continue]) -> 'a -> 'b t -> 'a indicated by the accumulator @since 0.8 *) +val fold_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a t -> 'acc * 'b t +(** [fold_map f acc a] is a [fold_left]-like function, but it also maps the + array to another array. + @since NEXT_RELEASE *) + +val scan_left : ('acc -> 'a -> 'acc) -> 'acc -> 'a t -> 'acc t +(** [scan_left f acc a] returns the array + [ [|acc; f acc x0; f (f acc a.(0)) a.(1); …|] ] + @since NEXT_RELEASE *) + + val iter : ('a -> unit) -> 'a t -> unit val iteri : (int -> 'a -> unit) -> 'a t -> unit