Rotate list in OCaml - list

I want to write a function rotate n l that returns a new list containing the same elements as l, "rotated" n times to the right. For example,
rotate 0 [1;2;3;4] should return [1;2;3;4]
rotate 1 [1;2;3;4] should return [4;1;2;3]
rotate 2 [1;2;3;4] should return [3;4;1;2]
rotate 3 [1;2;3;4] should return [2;3;4;1]
rotate 4 [1;2;3;4] should return [1;2;3;4]
etc.
The behavior of rotate n for n less than 0 should be the same as for n equal to 0.
I want to write this without using the list concatenation operator # from Pervasives.
Update: Here is the rotation function I wrote:
let rot1 l =
let rec iterate acc = function
[] -> []
| [x] -> x :: List.rev acc
| x :: l -> iterate (x :: acc) l
in
iterate [] l;;
But I want it to do the same thing without using List.rev.
Is there a way to do this?

Agree with Jeffrey, show us what you tried. Here's a small hint in case you need to get started. If you can write a function that performs only 1 rotation i.e. equivalent to rotate 1 l. (I call it one_rot). Then rotate can be easily defined as:
let rec rotate n l =
match n with
| 0 -> l
| _ -> rotate (n-1) (one_rot l)
Your solution is perfectly fine for me. Not sure what you have against List.rev but here's a completely stand alone one_rot. Note that we have to sacrifice tail recursion. You could probably make this quite a bit shorter too:
let rec last = function
| [] -> assert false
| [x] -> x
| x::xs -> last xs
let rec init = function
| [] -> []
| [x] -> []
| x::xs -> x::(init xs)
let one_rot l = (last l)::(init l)

This problem can be solved by combining these 3 functions:
cat(skip(list, places), take(list, places))
The implementation looks like:
let rec cat = function
([], y) -> y
| (x::xs, y) -> x :: cat (xs, y)
let rec skip = function
([], _) -> []
| (_::xs as xs1, c) -> if c > 0 then skip(xs, c - 1) else xs1
let rec take = function
([], _) -> []
| (x::xs, c) -> if c > 0 then x :: take(xs, c - 1) else []
let cycle l i =
cat (skip (l, i), take (l, i))
cycle ([1;2;3;4;5;6], 3);;
val it : int list = [4; 5; 6; 1; 2; 3]

Related

Delete elements between two occurrences in list

I have to make a function that take a list and return the list but without the elements betweens the occurences.
For example: [1; 2; 3; 4; 2; 7; 14; 21; 7; 5] -> [1; 2; 7; 5]
I imagined that to make this I will take the head of the list, and then see
if there is another occurrence in the tail, so I browse the list and when I found the occurrence, I delete everything between them and I keep just one of them.
First I tried something like this:
let rec remove list = match list with
| [] -> []
| h::t -> if(List.mem h t) then
(*Here I would like to go through the list element by element to
find the occurence and then delete everything between*)
else
remove t
So for the part I don't succeed to do, I made a function which allows to slice a list between two given points, just like so:
let slice list i k =
let rec take n = function
| [] -> []
| h :: t -> if n = 0 then [] else h :: take (n-1) t
in
let rec drop n = function
| [] -> []
| h :: t as l -> if n = 0 then l else drop (n-1) t
in
take (k - i + 1) (drop i list);;
(*Use: slice ["a";"b";"c";"d";"e";"f";"g";"h";"i";"j"] 2 3;;*)
I also have this function that allows me to get the index of points in the list:
let index_of e l =
let rec index_rec i = function
| [] -> raise Not_found
| hd::tl -> if hd = e then i else index_rec (i+1) tl
in
index_rec 0 l ;;
(*Use: index_of 5 [1;2;3;4;5;6] -> return 4*)
But I don't really know how to combine them to get what I expect.
here is what I made :
let rec remove liste =
let rec aux l el = match l with
| [] -> raise Not_found
| x :: xs -> if el = x then try aux xs el with Not_found -> xs
else aux xs el in
match liste with
| [] -> []
| x :: xs -> try let r = x :: aux xs x in remove r with Not_found -> x :: remove xs;;
my aux function return the list which follow the last occurence of el in l. If you have any question or if you need more explanation just ask me in comment
A version that uses an option type to tell if an element appears further on in the list:
let rec find_tail ?(eq = (=)) lst elem =
match lst with
| x :: _ when eq x elem -> Some lst
| _ :: xs -> find_tail ~eq xs elem
| [] -> None
let rec remove ?(eq = (=)) lst =
match lst with
| [x] -> [x]
| x :: xs -> begin
match find_tail ~eq xs x with
| Some tail -> x :: remove ~eq (List.tl tail)
| None -> x :: remove ~eq xs
end
| [] -> []
Also lets you specify a comparison function (Defaulting to =).

Adding Elements in List from Left OCaml

I have written a function:
let rec addAll f l =
match l with
| [] -> 0
| [x] -> x
| hd::tl -> let combined = addAll f tl in
f (hd) combined
;;
I works as titled, it will add all the elements of a list. However, I want to write this program so it is Left associative, so instead of combining the elements [1;2;3] as 1 - (2 - 3), I want it to be: (1 - 2) - 3.
Any hints on how I can make this forward recursive instead of tail? Or how can I make it so this function works as I intend? I know I could just reverse the list, but I want to try another way.
Your code does a right fold. Roughly speaking, it's like this:
let addAll f l = List.fold_right f l 0
You want to change it to a left fold. Roughly speaking you want this:
let addAll f l = List.fold_left f 0 l
Or, slightly more accurately you want:
let addAll f = function
| [] -> 0
| h :: t -> List.fold_left f h t
This second function does seem to do what you want:
# addAll (-) [1;2;3];;
- : int = -4
If you want to write it from scratch (not using List.fold_left), the easiest way is with an accumulator:
let addAllScratch f l =
let rec iadd f accum l =
match l with
| [] -> accum
| a::l -> iadd f (f accum a) l
in
match l with
| [] -> 0
| h :: t -> iadd f h t
This does do what you want:
# addAllScratch (-) [1;2;3];;
- : int = -4
(In essence, I just inserted the standard definition of List.fold_left into the code.)
let rec addAll f l =
match l with
| [] -> 0
| [x] -> x
| x::y::tl -> addAll f ((f x y)::tl)
;;
Test
# addAll (fun a b -> Printf.printf "(%d %d)" a b; a+b) [1;2;3];;
(1 2)(3 3)- : int = 6

how to rewrite code using tail recursion

I just looking for a little advice, how to rewrite code using tail recursion
open Core.Std;;
let rec dig x =
match x with
| 0 -> []
| _ -> x :: dig (x - 1)
;;
let () =
let numbers = dig 10 in
List.iter ~f:(Printf.printf "%d, ") numbers;
Printf.printf "\n";
;;
Any advice will be helpful
let dig x =
let rec f x s =
match x with
| 0 -> s
| _ -> f (x-1) (x::s)
f x []
Is this what you want? It's using tail recursion.
Edit:
for a decreasing seq, just replace (x::s) with (List.append s [x]) or (s # [x]) but it's NOT a good idea,and List.rev is better:
let dig x =
let rec f x s =
match x with
| 0 -> s
| _ -> f (x-1) (s # [x])
f x []
let dig x =
let rec f s z =
if z = x then s
else f (z::s) (z+1)
in
f [] 0
not sure if this floats your boat: You may have to tweak the border cases depending if you want 0 or the starting number included.
If you don't want to use List.rev after building the list backwards (which in my opinion is perfectly fine), nor starting your recursion with 0 instead of n, you can use some kind of continuation:
let dig2 x =
let rec aux x kont =
match x with
| 0 -> kont
| _ -> aux (x-1) (fun l -> kont (x::l))
in
aux x (fun l -> l) [];;
Basically each step returns a function that, given the list built by the remaining steps, will append x to it. We start the recursion with the identity function since we don't have anything to build yet. Then, when we exit from the recursion, we thus just have to apply the empty list to the obtained function.
Well, it seems to can have multiple solutions
open Core.Std;;
let rec digtail ?(l=[]) x =
match x with
| 0 -> l
| _ -> digtail ~l: (l # [x]) (x - 1)
;;
let () =
let numbers = digtail 10 in
List.iter ~f:(Printf.printf "%d, ") numbers;
Printf.printf "\n";
;;
Thanks to all, you helped a lot.

Adding up two lists in OCaml

Assume we use a list to represent number reversely, each node is a digit inside the number.
So [1;2;3;4;5] is the number 54321
Now we want to add up two such lists, e.g., adding [1;2] and [3;4], we get [4;6], which is the number 64.
here is my code:
let add l1 l2 =
let rec add_to up acc = function
| [] -> if up = 1 then 1::acc else acc
| hd::tl ->
let s = hd+up in
if s >= 10 then add_to 1 ((s-10)::acc) tl
else List.rev_append tl (s::acc)
and
add_up up acc = function
| [], [] -> if up = 1 then 1::acc else acc
| l, [] | [], l -> (add_to up [] l) # acc
| hd1::tl1, hd2::tl2 ->
let s = hd1+hd2+up in
if s >= 10 then add_up 1 ((s-10)::acc) (tl1, tl2)
else add_up 0 (s::acc) (tl1, tl2)
in
List.rev (add_up 0 [] (l1, l2))
The idea is very simple, just add two hds from two lists, and carry 1 to the next if the sum of two hds are bigger or equal with 10.
However, I think my code does not look beautiful.
we have the redundant part of the logic to solve the carry.
I have to do # on two lists.
Anyone can help me to make it more beautiful?
I think the trick is to generalize. The essence is to add three things, not two.
let sum a b =
let rec isum a b c =
match a, b with
| [], [] -> if c = 0 then [] else [c]
| [], x | x, [] -> isum [0] x c
| ah :: at, bh :: bt ->
let s = ah + bh + c in
(s mod 10) :: isum at bt (s / 10)
in
isum a b 0
This code isn't tail recursive. A tail recursive version will be a little less elegant.
Note: I assume you use [] to represent 0.

Insertion Sort implementation with one recursive function and foldBack function

I am reviewing implementations for some basic data structures and the algorithms operating on them. I guess the idiomatic F# code for Insertion Sort is very much like:
let rec insert x = function
| [] -> [x]
| y::ys -> if x<=y then x::y::ys
else y::(insert x ys)
and insertionSort = function
| [] -> []
| x::xs -> insert x (insertionSort xs)
let myLst = [8;3;3;5;-6;0;1;4;-3;2]
let result = myLst |> insertionSort
val result : int list = [-6; -3; 0; 1; 2; 3; 3; 4; 5; 8]
While I was trying to implement it with List.foldBack and only one recursive function, as below, and couldn't give me the correct result? Anyone can figure out where the problem lies?
let rec anotherInsertionSort lst =
List.foldBack(fun x (ys:list<_>) ->
if ys.IsEmpty then [x]
elif x <= ys.Head then x::ys
else ys.Head::x::anotherInsertionSort ys.Tail) lst []
Un-golfed from cfern's code:
let rec insert i = function
| h::t -> min h i::(insert (max h i) t)
| _ -> [i]
let insertionSort l = List.foldBack insert l []
As I said in my comment, the problem is that you're dropping x in your else branch. Here's one way to fix it:
let rec anotherInsertionSort lst =
List.foldBack(fun x ys ->
match ys with
| [] -> [x]
| y::_ when x <= y -> x::ys
| y::ys -> y::(anotherInsertionSort (x::ys))) lst []
Having said that, I like Daniel's approach better.