diff --git a/src/core/CCList.ml b/src/core/CCList.ml index 711ce521..8f6d0a8e 100644 --- a/src/core/CCList.ml +++ b/src/core/CCList.ml @@ -528,6 +528,37 @@ let take_drop n l = take n l, drop n l l1 @ l2 = l ) *) +let sublists_of_len ?(drop_short=true) ?offset n l = + if n < 1 then invalid_arg "sublists_of_len: n must be > 0"; + let offset = match offset with + | None -> n + | Some o when o < 1 -> invalid_arg "sublists_of_len: offset must be > 0" + | Some o -> o + in + (* add sub-lists of [l] to [acc] *) + let rec aux acc l = + let group = take n l in + if List.length group < n + then ( + (* this was the last group *) + if drop_short || group=[] then acc else group :: acc + ) else ( + let l' = drop offset l in + aux (group :: acc) l' (* continue *) + ) + in + List.rev (aux [] l) + +(*$= sublists_of_len as subs & ~printer:Q.Print.(list (list int)) + [[1;2;3]] (subs 3 [1;2;3;4]) + [[1;2]; [3;4]; [5;6]] (subs 2 [1;2;3;4;5;6]) + [] (subs 3 [1;2]) + [[1;2];[3;4]] (subs 2 ~offset:2 [1;2;3;4]) + [[1;2];[2;3]] (subs 2 ~offset:1 [1;2;3]) + [[1;2];[4;5]] (subs 2 ~offset:3 [1;2;3;4;5;6]) + [[1;2;3];[4]] (subs 3 ~drop_short:false [1;2;3;4]) +*) + let take_while p l = let rec direct i p l = match l with | [] -> [] diff --git a/src/core/CCList.mli b/src/core/CCList.mli index 0fb579af..5a10094c 100644 --- a/src/core/CCList.mli +++ b/src/core/CCList.mli @@ -95,6 +95,23 @@ val partition_map : ('a -> [<`Left of 'b | `Right of 'c | `Drop]) -> - if [f x = `Drop], ignores [x] @since 0.11 *) +val sublists_of_len : + ?drop_short:bool -> + ?offset:int -> + int -> + 'a list -> + 'a list list +(** [sublists_of_len n l] returns sub-lists of [l] that have length [n]. + By default, these sub-lists are non overlapping: + [sublists_of_len 2 [1;2;3;4;5;6]] returns [[1;2]; [3;4]; [5;6]] + @param drop_short if true, last elements are dropped if they do not + make a long enough list + @param offset the number of elements dropped between two consecutive + sub-lists. By default it is [n]. If [offset < n], the sub-lists + will overlap; if [offset > n], some elements will not appear at all. + @raise Invalid_argument if [offset <= 0] or [n <= 0] + @since NEXT_RELEASE *) + val pure : 'a -> 'a t val (<*>) : ('a -> 'b) t -> 'a t -> 'b t