I am currently learning OCaml and i couldn't make sublist even thought I can make a list without spaces as ['1'; '2'; '3'; '4'; '5'; '6']. I couldn't find any sources to my question so thanks for explaining it too please.
type chiffre = int (*0-9*);;
type chiffreCar = char (* '0' - '9'*)
type nombre = chiffre list;;
type txtnb = chiffreCar list ;;
let rec les_nb (a:txtnb) : txtnb =
match a with
| [] -> []
| ' ' :: tl -> les_nb(tl)
| hd::tl ->hd :: les_nb(tl) ;;
We can use a left fold to iterate over the list and group it by giving us an opportunity to use the accumulator to easily track the last item added to the output list.
This will build up the result list backwards and we'll get some empty lists where spaces repeat, but we can readily reverse those and filter out the empty lists.
# let lst = ['1'; '2'; '3'; ' '; ' '; '4'; '5'; ' '; '6'];;
val lst : char list = ['1'; '2'; '3'; ' '; ' '; '4'; '5'; ' '; '6']
# let group lst =
lst
|> List.fold_left
(fun i x ->
match i, x with
| [], ' ' -> i
| _, ' ' -> [] :: i
| [], _ -> [[x]]
| y::ys, _ -> (x :: y) :: ys)
[]
|> List.filter @@ (<>) []
|> List.rev
|> List.map List.rev;;
val group : char list -> char list list = <fun>
# group lst;;
- : char list list = [['1'; '2'; '3']; ['4'; '5']; ['6']]
Alternatively to:
|> List.rev
|> List.map List.rev;;
We can use List.rev_map
.
|> List.rev_map List.rev;;
Breaking down the call:
List.fold_left f [] ['1'; '2'; '3'; ' '; ' '; '4'; '5'; ' '; '6']
List.fold_left f [['1']] ['2'; '3'; ' '; ' '; '4'; '5'; ' '; '6']
List.fold_left f [['2'; '1']] ['3'; ' '; ' '; '4'; '5'; ' '; '6']
List.fold_left f [['3'; '2'; '1']] [' '; ' '; '4'; '5'; ' '; '6']
List.fold_left f [[]; ['3'; '2'; '1']] [' '; '4'; '5'; ' '; '6']
List.fold_left f [[]; []; ['3'; '2'; '1']] ['4'; '5'; ' '; '6']
List.fold_left f [['4']; []; ['3'; '2'; '1']] ['5'; ' '; '6']
List.fold_left f [['5'; '4']; []; ['3'; '2'; '1']] [' '; '6']
List.fold_left f [[]; ['5'; '4']; []; ['3'; '2'; '1']] ['6']
List.fold_left f [['6']; ['5'; '4']; []; ['3'; '2'; '1']] []
(List.filter @@ (<>) []) [['6']; ['5'; '4']; []; ['3'; '2'; '1']]
List.rev [['6']; ['5'; '4']; ['3'; '2'; '1']]
List.map List.rev [['3'; '2'; '1']; ['5'; '4']; ['6']]
[['1'; '2'; '3']; ['4'; '5']; ['6']]
If you wished to express this without using List.fold_left
, you might use an explicit accumulator. The pattern-matching maps over the same way.
# let rec group ?(acc=[]) lst =
match acc, lst with
| _, [] -> List.(rev @@ map rev @@ filter ((<>) []) acc)
| _, ' '::xs -> group ~acc: ([] :: acc) xs
| [], x::xs -> group ~acc: [[x]] xs
| y::ys, x::xs -> group ~acc: ((x :: y) :: ys) xs;;
val group : ?acc:char list list -> char list -> char list list = <fun>
# group lst;;
- : char list list = [['1'; '2'; '3']; ['4'; '5']; ['6']]
A further development of this would be to pass a function to act as a predicate to determine what to group, and to leverage sequences.
E.g.
# let rec group_seq f seq =
let rec aux ?(acc=[]) seq () =
match seq () with
| Seq.Nil when acc = [] -> Seq.Nil
| Seq.Nil -> Seq.Cons (List.rev acc, Seq.empty)
| Seq.Cons (x, seq') when f x -> aux ~acc: (x :: acc) seq' ()
| Seq.Cons (x, seq') when acc = [] -> aux seq' ()
| Seq.Cons (x, seq') -> Seq.Cons (List.rev acc, aux seq')
in
aux seq;;
val group_seq : ('a -> bool) -> 'a Seq.t -> 'a list Seq.t = <fun>
# ['1'; '2'; '3'; ' '; ' '; '4'; '5'; ' '; '6']
|> List.to_seq
|> group_seq ((<>) ' ')
|> List.of_seq;;
- : char list list = [['1'; '2'; '3']; ['4'; '5']; ['6']]
# "123 45 6"
|> String.to_seq
|> group_seq ((<>) ' ')
|> List.of_seq;;
- : char list list = [['1'; '2'; '3']; ['4'; '5']; ['6']]
# "123 45 6"
|> String.to_seq
|> group_seq (fun ch -> ch <> ' ' && ch <> '3')
|> List.of_seq;;
- : char list list = [['1'; '2']; ['4'; '5']; ['6']]