feat(list): add indexed functions and fold_on_map

close #222
This commit is contained in:
Simon Cruanes 2019-12-14 16:52:35 -06:00
parent 1947d1804b
commit 7d9d9d45b8
4 changed files with 112 additions and 1 deletions

View file

@ -233,6 +233,28 @@ let fold_map f acc l =
fold_map (fun acc x -> x::acc, x) [] l = (List.rev l, l)) fold_map (fun acc x -> x::acc, x) [] l = (List.rev l, l))
*) *)
let fold_map_i f acc l =
let rec aux f acc i map_acc l = match l with
| [] -> acc, List.rev map_acc
| x :: l' ->
let acc, y = f acc i x in
aux f acc (i+1) (y :: map_acc) l'
in
aux f acc 0 [] l
let fold_on_map ~f ~reduce acc l =
let rec aux acc l = match l with
| [] -> acc
| x :: l' ->
let acc = reduce acc (f x) in
aux acc l'
in
aux acc l
(*$=
6 (fold_on_map ~f:int_of_string ~reduce:(+) 0 ["1";"2";"3"])
*)
let scan_left f acc l = let scan_left f acc l =
let rec aux f acc l_acc l = match l with let rec aux f acc l_acc l = match l with
| [] -> List.rev l_acc | [] -> List.rev l_acc
@ -290,6 +312,15 @@ let fold_filter_map f acc l =
0 (1--10)) 0 (1--10))
*) *)
let fold_filter_map_i f acc l =
let rec aux f acc i map_acc l = match l with
| [] -> acc, List.rev map_acc
| x :: l' ->
let acc, y = f acc i x in
aux f acc (i+1) (cons_maybe y map_acc) l'
in
aux f acc 0 [] l
let fold_flat_map f acc l = let fold_flat_map f acc l =
let rec aux f acc map_acc l = match l with let rec aux f acc map_acc l = match l with
| [] -> acc, List.rev map_acc | [] -> acc, List.rev map_acc
@ -305,6 +336,15 @@ let fold_flat_map f acc l =
fold_flat_map (fun acc x->acc+x, [pf "%d" x; pf "a%d" x]) 0 [1;2;3]) fold_flat_map (fun acc x->acc+x, [pf "%d" x; pf "a%d" x]) 0 [1;2;3])
*) *)
let fold_flat_map_i f acc l =
let rec aux f acc i map_acc l = match l with
| [] -> acc, List.rev map_acc
| x :: l' ->
let acc, y = f acc i x in
aux f acc (i+1) (List.rev_append y map_acc) l'
in
aux f acc 0 [] l
(*$Q (*$Q
Q.(list int) (fun l -> \ Q.(list int) (fun l -> \
fold_flat_map (fun acc x -> x::acc, [x;x+10]) [] l = \ fold_flat_map (fun acc x -> x::acc, [x;x+10]) [] l = \
@ -387,6 +427,25 @@ let flat_map f l =
List.length (flat_map (fun x->[x]) (1--300_000)) = 300_000 List.length (flat_map (fun x->[x]) (1--300_000)) = 300_000
*) *)
let flat_map_i f l =
let rec aux f i l kont = match l with
| [] -> kont []
| x::l' ->
let y = f i x in
let kont' tail = match y with
| [] -> kont tail
| [x] -> kont (x :: tail)
| [x;y] -> kont (x::y::tail)
| l -> kont (append l tail)
in
aux f (i+1) l' kont'
in
aux f 0 l (fun l->l)
(*$=
[1;2;2;3;3;3] (flat_map_i (fun i x->replicate (i+1) x) [1;2;3])
*)
let flatten l = fold_right append l [] let flatten l = fold_right append l []
(*$T (*$T

View file

@ -73,6 +73,16 @@ val fold_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a list -> 'acc * 'b list
list to another list. list to another list.
@since 0.14 *) @since 0.14 *)
val fold_map_i : ('acc -> int -> 'a -> 'acc * 'b) -> 'acc -> 'a list -> 'acc * 'b list
(** [fold_map_i f init l] is a [foldi]-like function, but it also maps the
list to another list.
@since NEXT_RELEASE *)
val fold_on_map : f:('a -> 'b) -> reduce:('acc -> 'b -> 'acc) -> 'acc -> 'a list -> 'acc
(** [fold_on_map ~f ~reduce init l] combines [map f] and [fold_left reduce init]
in one operation.
@since NEXT_RELEASE *)
val scan_left : ('acc -> 'a -> 'acc) -> 'acc -> 'a list -> 'acc list val scan_left : ('acc -> 'a -> 'acc) -> 'acc -> 'a list -> 'acc list
(** [scan_left f init l] returns the list [[init; f init x0; f (f init x0) x1; ...]] (** [scan_left f init l] returns the list [[init; f init x0; f (f init x0) x1; ...]]
where [x0], [x1], etc. are the elements of [l]. where [x0], [x1], etc. are the elements of [l].
@ -89,11 +99,21 @@ val fold_filter_map : ('acc -> 'a -> 'acc * 'b option) -> 'acc -> 'a list -> 'ac
generates a list of output in a way similar to {!filter_map}. generates a list of output in a way similar to {!filter_map}.
@since 0.17 *) @since 0.17 *)
val fold_filter_map_i : ('acc -> int -> 'a -> 'acc * 'b option) -> 'acc -> 'a list -> 'acc * 'b list
(** [fold_filter_map_i f init l] is a [foldi]-like function, but also
generates a list of output in a way similar to {!filter_map}.
@since NEXT_RELEASE *)
val fold_flat_map : ('acc -> 'a -> 'acc * 'b list) -> 'acc -> 'a list -> 'acc * 'b list val fold_flat_map : ('acc -> 'a -> 'acc * 'b list) -> 'acc -> 'a list -> 'acc * 'b list
(** [fold_flat_map f acc l] is a [fold_left]-like function, but it also maps the (** [fold_flat_map f acc l] is a [fold_left]-like function, but it also maps the
list to a list of lists that is then [flatten]'d. list to a list of lists that is then [flatten]'d.
@since 0.14 *) @since 0.14 *)
val fold_flat_map_i : ('acc -> int -> 'a -> 'acc * 'b list) -> 'acc -> 'a list -> 'acc * 'b list
(** [fold_flat_map_i f acc l] is a [fold_left]-like function, but it also maps the
list to a list of lists that is then [flatten]'d.
@since NEXT_RELEASE *)
val count : ('a -> bool) -> 'a list -> int val count : ('a -> bool) -> 'a list -> int
(** [count p l] counts how many elements of [l] satisfy predicate [p]. (** [count p l] counts how many elements of [l] satisfy predicate [p].
@since 1.5, but only @since 1.5, but only
@ -150,6 +170,12 @@ val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
val flat_map : ('a -> 'b t) -> 'a t -> 'b t val flat_map : ('a -> 'b t) -> 'a t -> 'b t
(** Map and flatten at the same time (safe). Evaluation order is not guaranteed. *) (** Map and flatten at the same time (safe). Evaluation order is not guaranteed. *)
val flat_map_i : (int -> 'a -> 'b t) -> 'a t -> 'b t
(** Map with index and flatten at the same time (safe).
Evaluation order is not guaranteed.
@since NEXT_RELEASE
*)
val flatten : 'a t t -> 'a t val flatten : 'a t t -> 'a t
(** Safe flatten. Concatenate a list of lists. *) (** Safe flatten. Concatenate a list of lists. *)

View file

@ -73,6 +73,16 @@ val fold_map : f:('acc -> 'a -> 'acc * 'b) -> init:'acc -> 'a list -> 'acc * 'b
list to another list. list to another list.
@since 0.14 *) @since 0.14 *)
val fold_map_i : f:('acc -> int -> 'a -> 'acc * 'b) -> init:'acc -> 'a list -> 'acc * 'b list
(** [fold_map_i f init l] is a [foldi]-like function, but it also maps the
list to another list.
@since NEXT_RELEASE *)
val fold_on_map : f:('a -> 'b) -> reduce:('acc -> 'b -> 'acc) -> init:'acc -> 'a list -> 'acc
(** [fold_on_map ~f ~reduce init l] combines [map f] and [fold_left reduce init]
in one operation.
@since NEXT_RELEASE *)
val scan_left : f:('acc -> 'a -> 'acc) -> init:'acc -> 'a list -> 'acc list val scan_left : f:('acc -> 'a -> 'acc) -> init:'acc -> 'a list -> 'acc list
(** [scan_left ~f ~init l] returns the list [[init; f init x0; f (f init x0) x1; ...]] (** [scan_left ~f ~init l] returns the list [[init; f init x0; f (f init x0) x1; ...]]
where [x0], [x1], etc. are the elements of [l]. where [x0], [x1], etc. are the elements of [l].
@ -89,11 +99,21 @@ val fold_filter_map : f:('acc -> 'a -> 'acc * 'b option) -> init:'acc -> 'a list
generates a list of output in a way similar to {!filter_map}. generates a list of output in a way similar to {!filter_map}.
@since 0.17 *) @since 0.17 *)
val fold_filter_map_i : f:('acc -> int -> 'a -> 'acc * 'b option) -> init:'acc -> 'a list -> 'acc * 'b list
(** [fold_filter_map_i f init l] is a [foldi]-like function, but also
generates a list of output in a way similar to {!filter_map}.
@since NEXT_RELEASE *)
val fold_flat_map : f:('acc -> 'a -> 'acc * 'b list) -> init:'acc -> 'a list -> 'acc * 'b list val fold_flat_map : f:('acc -> 'a -> 'acc * 'b list) -> init:'acc -> 'a list -> 'acc * 'b list
(** [fold_flat_map f acc l] is a [fold_left]-like function, but it also maps the (** [fold_flat_map f acc l] is a [fold_left]-like function, but it also maps the
list to a list of lists that is then [flatten]'d. list to a list of lists that is then [flatten]'d.
@since 0.14 *) @since 0.14 *)
val fold_flat_map_i : f:('acc -> int -> 'a -> 'acc * 'b list) -> init:'acc -> 'a list -> 'acc * 'b list
(** [fold_flat_map_i f acc l] is a [fold_left]-like function, but it also maps the
list to a list of lists that is then [flatten]'d.
@since NEXT_RELEASE *)
val count : f:('a -> bool) -> 'a list -> int val count : f:('a -> bool) -> 'a list -> int
(** [count p l] counts how many elements of [l] satisfy predicate [p]. (** [count p l] counts how many elements of [l] satisfy predicate [p].
@since 1.5, but only @since 1.5, but only
@ -150,6 +170,12 @@ val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
val flat_map : f:('a -> 'b t) -> 'a t -> 'b t val flat_map : f:('a -> 'b t) -> 'a t -> 'b t
(** Map and flatten at the same time (safe). Evaluation order is not guaranteed. *) (** Map and flatten at the same time (safe). Evaluation order is not guaranteed. *)
val flat_map_i : f:(int -> 'a -> 'b t) -> 'a t -> 'b t
(** Map with index and flatten at the same time (safe).
Evaluation order is not guaranteed.
@since NEXT_RELEASE
*)
val flatten : 'a t t -> 'a t val flatten : 'a t t -> 'a t
(** Safe flatten. Concatenate a list of lists. *) (** Safe flatten. Concatenate a list of lists. *)

View file

@ -40,7 +40,7 @@ type 'a sequence = ('a -> unit) -> unit
@deprecate see {!iter} instead *) @deprecate see {!iter} instead *)
[@@ocaml.deprecated "see iter"] [@@ocaml.deprecated "see iter"]
type 'a sequence_once = 'a sequence type 'a sequence_once = 'a iter
(** Iter that should be used only once (** Iter that should be used only once
@deprecate see {!iter_once} instead *) @deprecate see {!iter_once} instead *)
[@@ocaml.deprecated "see iter_once"] [@@ocaml.deprecated "see iter_once"]