6.3 KiB
99 Ocaml Problems
- #1 Tail of a list
- #2 Last two elements of a list
- #3 N'th element of a list
- #4 Find the number of elements of a list.
- #5 Reverse a list.
- #6 Palindrome
- #7 Flatten a list
- #8 Eliminate duplicates
- #9 Pack consecutive duplicates
- #10 Run-length encoding
- #11 Modified run-length encoding
- #12 Decode a run-length encoded list
#1 Tail of a list
Write a function last : 'a list -> 'a option
that returns the last element of a
list
# last ["a" ; "b" ; "c" ; "d"];;
- : string option = Some "d"
# last [];;
- : 'a option = None
Solution
let rec last = function
| [] -> None
| [x] -> Some x
| _::xs -> last xs
#2 Last two elements of a list
Find the last but one (last and penultimate) elements of a list.
# last_two ["a"; "b"; "c"; "d"];;
- : (string * string) option = Some ("c", "d")
# last_two ["a"];;
- : (string * string) option = None
Solution
let rec last_two = function
| [] | [_] -> None
| [x;y] -> Some (x,y)
| _::xs -> last_two xs
#3 N'th element of a list
Find the N'th element of a list.
REMARK: OCaml has List.nth which numbers elements from 0 and raises an exception if the index is out of bounds.
# List.nth ["a"; "b"; "c"; "d"; "e"] 2;;
- : string = "c"
# List.nth ["a"] 2;;
Exception: Failure "nth".
Solution
let rec nth index = function
| [] -> failwith "nth"
| x::xs -> if index = 0 then x else nth (index - 1) xs
#4 Find the number of elements of a list.
OCaml standard library has List.length but we ask that you reimplement it. Bonus for a tail recursive solution.
# length ["a"; "b"; "c"];;
- : int = 3
# length [];;
- : int = 0
Solution
let length list =
let rec length_rec acc = function
| [] -> acc
| _::xs -> length_rec (acc + 1) xs
in length_rec 0 list
#5 Reverse a list.
OCaml standard library has List.rev but we ask that you reimplement it.
# rev ["a"; "b"; "c"];;
- : string list = ["c"; "b"; "a"]
Solution
let rev (list: int list) =
let rec rev acc = function
| [] -> acc
| x::xs -> rev (x::acc) xs
in rev [] list
#6 Palindrome
Find out whether a list is a palindrome.
HINT: a palindrome is its own reverse.
# is_palindrome ["x"; "a"; "m"; "a"; "x"];;
- : bool = true
# not (is_palindrome ["a"; "b"]);;
- : bool = true
Solution
let is_palindrome list = list = List.rev list
#7 Flatten a list
Flatten a nested list structure.
type 'a node =
| One of 'a
| Many of 'a node list
# flatten [One "a"; Many [One "b"; Many [One "c" ;One "d"]; One "e"]];;
- : string list = ["a"; "b"; "c"; "d"; "e"]
Solution
let flatten nodes =
let rec f = function
| One x -> [x]
| Many xs -> List.concat_map f xs
in nodes |> List.concat_map f
(* Or without List.concat_map *)
let flatten2 nodes =
let rec f acc = function
| [] -> acc
| One n::ns -> f (n::acc) ns
| Many ns::rest -> f (f acc ns) rest
in f [] nodes |> List.rev
#8 Eliminate duplicates
Eliminate consecutive duplicates of list elements.
# compress ["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "e"; "e"; "e"; "e"];;
- : string list = ["a"; "b"; "c"; "a"; "d"; "e"]
Solution
let compress list =
let rec f acc list =
match (list, acc) with
| [] , _ -> acc
| x::xs , y::_ when x = y -> f acc xs
| x::xs , _ -> f (x::acc) xs
in f [] list |> List.rev
#9 Pack consecutive duplicates
Pack consecutive duplicates of list elements into sublists.
# pack ["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "d"; "e"; "e"; "e"; "e"];;
- : string list list =
[["a"; "a"; "a"; "a"]; ["b"]; ["c"; "c"]; ["a"; "a"]; ["d"; "d"];
["e"; "e"; "e"; "e"]]
Solution
let rec pack list =
let rec f acc1 acc2 = function
| [] -> []
| [x] -> (x::acc1)::acc2
| x::(y::xs as tail) ->
if x = y
then f (x::acc1) acc2 tail
else f [] ((x::acc1)::acc2) tail
in f [] [] list |> List.rev
#10 Run-length encoding
If you need so, refresh your memory about run-length encoding.
Here is an example:
# encode ["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "e"; "e"; "e"; "e"];;
- : (int * string) list =
[(4, "a"); (1, "b"); (2, "c"); (2, "a"); (1, "d"); (4, "e")]
Solution
let encode = function
| [] -> []
| list ->
let rec f (count, item) acc2 = function
| [x] -> (count, item)::acc2
| x::(y::xs as tail) when x = y -> f (count + 1, item) acc2 tail
| x::(y::xs as tail) -> f (1, y) ((count, item)::acc2) tail
| [] -> []
in f (1, List.nth list 0) [] list |> List.rev
#11 Modified run-length encoding
Modify the result of the previous problem in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.
Since OCaml lists are homogeneous, one needs to define a type to hold both single elements and sub-lists.
type 'a rle =
| One of 'a
| Many of int * 'a
# encode ["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "e"; "e"; "e"; "e"];;
- : string rle list =
[Many (4, "a"); One "b"; Many (2, "c"); Many (2, "a"); One "d"; Many (4, "e")]
Solution
let encode = function
| [] -> []
| list ->
let rec f (count, elem) acc2 = function
| [] -> []
| [x] when count = 0 -> (One x)::acc2
| [x] -> (Many (count + 1, x))::acc2
| x::(y::xs as tail) when x = y -> f (count + 1, elem) acc2 tail
| x::(y::xs as tail) when count = 0 -> f (0, y) ((One x)::acc2) tail
| x::(y::xs as tail) -> f (0, y) ((Many (count + 1, x))::acc2) tail
in f (0, List.nth list 0) [] list |> List.rev
#12 Decode a run-length encoded list
Given a run-length code list generated as specified in the previous problem, construct its uncompressed version.
# decode [Many (4, "a"); One "b"; Many (2, "c"); Many (2, "a");
One "d"; Many (4, "e")];;
- : string list =
["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "e"; "e"; "e"; "e"]
Solution