Reverse list elements at even positions - ocaml

I know already know how to reverse a list "manually-coded":
let rev_list l =
let rec rev_acc acc = function
| [] -> acc
| hd::tl -> rev_acc (hd::acc) tl
in
rev_acc [] l
And now i try to reverse only those elements that are at even positions, thats mean that for input:
Function([0;1;2;3;4;5;6;7])
return is:
[6;1;4;3;2;5;0;7]
How can i do this if we assume that we count elements from 0?

(* integrate [x1;x2;x3] [y1;y2;y3] = [x1;y1;x2;y2;x3;y3] *)
let integrate l1 l2 =
let rec integrt acc = function
| [], [] -> List.rev acc
| hd::tl,[] | [], hd::tl -> integrt (hd::acc) (tl,[])
| hd1::tl1, hd2::tl2 -> integrt (hd2::hd1::acc) (tl1,tl2)
in
integrt [] (l1,l2)
let rev_list_even_pos l=
let rec rev r_acc acc i = function
| [] -> integrate r_acc (List.rev acc)
| hd::tl ->
if i mod 2 = 0 then rev (hd::r_acc) acc (i+1) tl
else rev r_acc (hd::acc) (i+1) tl
in
rev [] [] 0 l
The trick is to use two separate lists: one stores the reversed elements, the other store elements in original order.

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 =).

F# - splitting list into tuple of odd-even lists (by element, not position)

Example: split [1;3;2;4;7;9];;
Output: ([1;3;7;9], [2;4])
I'm new to F# and I can't figure it out.
Can't use the partition built in function.
This is what I have so far:
let rec split xs =
match xs with
| [] -> [], []
| xs -> xs, []
| xh::xt -> let odds, evens = split xt
if (xh % 2) = 0 then xh::odds, xh::evens
else xh::odds, evens
Fixed code:
let rec split xs =
match xs with
| [] -> [], []
| xh::xt -> let odds, evens = split xt
if (xh % 2) = 0 then odds, xh::evens
else xh::odds, evens
*Thanks to #TheInnerLight for pointing out my errors: unreachable case and unnecessarily modifying odds
You can use the built-in List.partition function
let splitOddEven xs =
xs |> List.partition (fun x -> x % 2 <> 0)
splitOddEven [1;3;2;4;7;9];;
val it : int list * int list = ([1; 3; 7; 9], [2; 4])
If you want a recursive implementation, I'd probably go for a tail recursive implementation like this:
let splitOddEven xs =
let rec splitOddEvenRec oddAcc evenAcc xs =
match xs with
| [] -> oddAcc, evenAcc
| xh::xt ->
if (xh % 2) = 0 then splitOddEvenRec oddAcc (xh :: evenAcc) xt
else splitOddEvenRec (xh :: oddAcc) evenAcc xt
splitOddEvenRec [] [] xs
splitOddEven [1;3;2;4;7;9]
Note that this will give you the two resulting lists in reverse order so you might wish to reverse them yourself.

count number of duplicates in a list in OCaml

I have a list like:
let lst = ["cat"; "dog"; "cow"; "dog"; "cat"; "horse"; "dog"];;
I want to count the number of same elements and have the output in a list of tuples (element, count) like:
[("cat", 2); ("dog", 3); ("cow", 1); ("horse", 1)]
I tried using List.fold_left but found that the folding function will be complex. Any suggestion?
If you don't care about performance, then it can be like this:
let count_dup l =
let scan_count x l = List.fold_left (fun (c,acc) y -> if x = y then c+1,acc else c,y::acc) (1,[]) l in
let rec count acc = function
| [] -> List.rev acc
| hd::tl -> let c,r = scan_count hd tl in count ((hd,c)::acc) r
in
count [] l
If you care about performance, but don't care about the order, then it is better that you sort the list first, then scan once.
let count_dup' l =
let sl = List.sort compare l in
match sl with
| [] -> []
| hd::tl ->
let acc,x,c = List.fold_left (fun (acc,x,c) y -> if y = x then acc,x,c+1 else (x,c)::acc, y,1) ([],hd,1) tl in
(x,c)::acc
let count l =
let hash = Hashtbl.create 10 in
List.iter (fun key -> if Hashtbl.mem hash key then Hashtbl.replace hash key ((Hashtbl.find hash key) + 1) else Hashtbl.add hash key 1) l;
Hashtbl.fold (fun k v ls -> (k, v) :: ls) hash []
A way to preserve order and performance:
let count lst =
let sorted = List.sort (compare) lst in
List.fold_right (fun ele acc -> match acc with
| [] -> [(ele, 1)]
| (ele', c)::t ->
if ele = ele'
then (ele, c+1)::t
else (ele,1)::(ele',c)::t) sorted []

last element in list using ocaml List.fold_left

I can find the last element of a list by the following code.
let last (xs:'a list) : 'a =
let rec aux xs prev =
match xs with
| [] -> prev
| x::ys -> aux ys x in
match xs with
| [] -> failwith "no element"
| x::xs -> aux xs x
How do I find the last element of the same list using the List.fold_left function in OCaml?
Thanks in advance!
fold_left accesses the list from the head to the tail, thus the function passed to fold_left should just replace the accumulator with the current element of the list. Thus simply,
let last = function
| x::xs -> List.fold_left (fun _ y -> y) x xs
| [] -> failwith "no element"
You can write your function directly, without the aux function.
let rec last = function
| x::[] -> x
| _::xs -> last xs
| [] -> failwith "no element"

OCaml: swapping elements in a list

I'm wondering how can I write a function that divides a given list to sublists in a given point, swaps these sublists and returns a resulting list.
For example:
swap([1;3;5;6],2) => [5;6;1;3]
I suppose that the code that I developed is correct?
let rec swap (l,n) =
let rec loop t (count,laux) =
match t with
| h::t when count < n -> loop t (count+1, h::laux)
| h::t -> h::t# List.rev laux
| []->[]
in
loop l (0,[])
;;
You're almost there. The problem is your function handles the case when length of l is greater or equals to n incorrectly.
The pattern [] doesn't mean input list is empty; it means we come to the end of the list. What you should do at that point is returning the accumulator acc in the reverse order.
I rearrange patterns a little bit so base cases come first:
let rec swap (l, n) =
let rec loop xs count acc =
match xs with
| _ when count = n -> xs # List.rev acc
| [] -> List.rev acc
| h::t -> loop t (count+1) (h::acc)
in loop l 0 []