F# Recursive Functions: make list items unique - list

let rec isolate (l:'a list) =
match l with
| [] -> []
| x::xs ->
if memberof(x,xs)
then remove (x,l)
else isolate xs
I've already created functions memberof and remove, the only problem is that when line 6 remove(x,l) executes it doesn't continue with isolate(xs) for continued search through the list.
Is there a way to say,
if x then f(x) and f(y)
?

As you are using F# immutable lists, the result of remove needs to be stored somewhere:
let rec isolate (l:'a list) =
match l with
| [] -> []
| x::xs ->
if memberof(x,xs)
then
let xs = remove (x,l)
isolate xs
else isolate xs
To answer your more general question:
let f _ = ()
let f' z = z
let x = true
let y = 42
let z = 3.141
if x then
f y
f' z |> ignore
The ignore is needed here because in F# there are no statements, just expressions, so you can think of if x then f' z as
if x then
f' z
else
()
and thus the first branch needs to return () as well.

In addition to CaringDev's answer.
You may look at this simple solution.
It is worth note, that it's not a fastest way to do this.
let rec isolate (acc : 'a list) (l : 'a list) =
match l with
| [] -> acc
| head :: tail ->
if memberof (head, tail)
then remove (head, tail) |> isolate (acc # [head])
else isolate (acc # [head]) tail
let recursiveDistinct = isolate []
let uniqValues = recursiveDistinct [ 1; 1; 2; 3] //returns [1;2;3]

let isolate list =
let rec isolateInner searchList commonlist =
match searchList with
| x::xs ->
if (memberof commonlist x) then
isolateInner xs commonlist
else
let commonlist = (x :: commonlist)
isolateInner xs commonlist
| [] -> reverse commonlist
isolateInner list []
This is part of an answer to your larger problem.
Notice that this does not use remove. Since you have to pass over each item in the original list and list are immutable, it is better to create a new list and only add the unique items to the new list, then return the new list.

Related

replace all the n occurences in a list per a given list - ocaml

example remplace_par_liste 2 [-4;-5] [1;2;3;2;2;9] --> [1;-4;-5;3;-4;-5-4;-5;9]
I know how to do it with an occurence but not with a list.
example remplace 2 0 [1;2;3;2;2;9] --> [1; 0; 3; 0; 0; 9]
let listere = [1;2;3;2;2;9];;
let rec remplace n p liste = match liste with
[] -> []
|a::q -> (if a = n then p else a)::(remplace n p q);;
remplace 2 0 listere;;
- : int list = [1; 0; 3; 0; 0; 9]
And there is the problem, i need another funtion to insert the list l1 in the list ?
let listerel = [1;2;3;2;2;9];;
let l1 = [-4;-5];;
let rec remplace_par_liste n l1 liste = match liste with
[] -> []
(|a::q -> (if a = n then l1 else a)::(remplace_par_liste n l1 q);;)
remplace_par_liste 2 l1 listerel;;
File "", line 4, characters 113-114:
Error: This expression has type int list
but an expression was expected of type int```
I would suggest you define the second function first.
:: will let us add x to the front of the list created by recursively running the function on the tail of the list.
# will let us concatenate two lists so we can insert the values in the substitute list into the result.
let rec replace_value_with_list v sub lst =
match lst with
| [] -> []
| x::xs when x <> v -> x :: replace_value_with_list v sub xs
| x::xs -> sub # replace_value_with_list v sub xs
The first function is then much simpler, being just a specialized application of the second, putting that single value into a list.
let replace_value v sub lst =
replace_value_with_list v [sub] lst
Downsides to this implementation
I have decided to edit to mention this based on the comments. The above is not tail-recursive. Each time a function is called, it takes up a certain amount of stack space. The stack is limited. Recursively call a function or functions too many times and you will get a stack overflow error.
OCaml (and some other programming languages, primarily in the functional vein) offer tail-call optimization. If the compiler can determine that the last thing a function does is call itself or another function, then the space the caller occupies on the stack can be reused.
We can modify the existing function from ealier.
let rec replace_value_with_list v sub lst =
match lst with
| [] -> []
| x::xs when x <> v -> x :: replace_value_with_list v sub xs
| x::xs -> sub # replace_value_with_list v sub xs
This operation, for instance, makes the function non-tail-recursive:
x :: replace_value_with_list v sub xs
First we have to call replace_value_with_list v sub xs and then add x to the front of it. We can solve this issue by passing along an accumulator that builds up the list. We can hide this detail by using a local auxiliary function. Because the local function is taking care of the recursion, replace_value_with_list no longer needs to be marked as recursive.
let replace_value_with_list v sub lst =
let rec aux v sub lst acc =
match lst with
| [] -> List.rev acc
| x::xs when x <> v -> aux v sub xs (x :: acc)
| x::xs -> replace_value_with_list v sub xs (sub # acc)
in
aux v sub lst []
Note that when we call the aux function, it will build up the accumulator in the reverse order to the way we expect, so we need to reverse the accumulator on the exit condition.
However, this is still not optimal because the # operator which performs the concatenation is not tail-recursive. We can overcome this by replacing # with List.rev_append which is tail-recursive.
let replace_value_with_list v sub lst =
let rec aux v sub lst acc =
match lst with
| [] -> List.rev acc
| x::xs when x <> v -> aux v sub xs (x::acc)
| x::xs -> aux v sub xs (List.rev_append sub acc)
in
aux v sub lst []
This process of iterating over a list and accumulating a value is where folds really shine.
let rvl v sub lst =
List.(
let f acc x = if x <> v then x::acc else rev_append sub acc in
fold_left f [] lst |> rev
)

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

Removing consecutive duplicates from a list without recursion

I'm supposed to remove consecutive duplicates from an int list without using recursion and using only List.fold, map, filter, fold_left, fold_right.
I almost got it, but the problem with my code is that it checks if each element equals the 2nd element, and not the next element.
For example if let z = int list [3;1;4;5;5;1;1] my code will return [3;4;5] and not [3;1;4;5;1]. I'm not sure how to change it so filter uses a dynamically changing list parameter and not simply the original one (so it doesn't compare each element to the second element (1 in this case) each time):
let dupe (ls: int list) : int list =
List.filter (fun x -> if List.length ls = 0 then true else if x = List.hd (List.tl xs) then false else true) ls
The type of List.filter is this:
# List.filter;;
- : ('a -> bool) -> 'a list -> 'a list = <fun>
Notably, the filter function can see only one element of the list at a time. You need to see two consecutive elements to decide what to do, so I'd say List.filter won't do the job.
You're going to have to use map or one of the folds, I'd say. You can figure out which one(s) will work, with similar reasoning.
(I assume this is the sort of reasoning the assignment is supposed to illustrate. So I'm going to leave it there.)
Without rec
let remove = function
[] -> []
| x::tl ->
let (_,lxRes)=
List.fold_left (
fun (xPrec,lxRes) xCour ->
if xPrec=xCour then
(xCour,lxRes)
else
(xCour,lxRes#[xCour])
) (x+1,[]) (x::tl)
in
lxRes
Test:
# remove [3;1;4;5;5;1;1];;
- : int list = [3; 1; 4; 5; 1]
# remove [1;1];;
- : int list = [1]
# remove [1;1;1;1;2;2;3;4;5;5];;
- : int list = [1; 2; 3; 4; 5]
With rec (just for information)
let rec remove =
function
| [] -> []
| x::[] -> x::[]
| x::y::tl ->
if x=y then remove (y::tl)
else x::remove (y::tl)
Using just List.fold_left can be a little bit more concise than the previous answer. Of course, this will build up the list in reverse order, so we need to reverse the result.
let remove lst =
List.(
lst
|> fold_left
(fun acc x ->
match acc with
| [] -> [x]
| hd::_ when x = hd -> acc
| _ -> x::acc)
[]
|> rev
)
Of course, if you're not allowed to use List.rev we can reimplement it easily using List.fold_left, List.cons and Fun.flip.
let rev lst =
List.fold_left (Fun.flip List.cons) [] lst

"deleteAll" method only removes one occurrence

I've been asked to write a Standard ML Program which deletes every occurrence of a list from another list. For the life of me I cannot understand what is wrong with my code. Any help would be appreciated!
My input for this program is as follows:
deleteAll [1,2,3] [3,2,1,2,3,2,1,2,3];
However my output is this:
val it = [3,2,2,1,2,3] : int list
When it should be: [3,2,2];
fun length(x) = if x = [] then 0 else 1+length(tl(x));
val length = fn : ''a list -> int
fun drop 0 L = L
| drop n [] = raise c4
| drop n (h::t) = drop (n-1) t;
val drop = fn : int -> 'a list -> 'a list
fun starts [] _ = true
| starts _ [] = false
| starts (h::t) (x::xs) = if(h=x) then starts t xs else false;
val starts = fn : ''a list -> ''a list -> bool
fun deleteAll [] _ = []
| deleteAll xs [] = xs
| deleteAll (x::xs) (y::ys) = if(starts (x::xs) (y::ys))
then deleteAll (x::xs) (drop (length(x::xs)) (y::ys))
else y::(deleteAll (x::xs) ys);
val deleteAll = fn : ''a list -> ''a list -> ''a list
First you don't need to create a length function as length is a build-in function that returns an int representing the elements of an 'a list.
One more thing, you raise an exception c4 in your function drop. Then you should also include that in the beginning of your program.
The primary reason your code doesn't work is your deleteAll function base cases. The corrected version should be:
fun deleteAll [] xs = xs (* when the first list is empty, it should return the original list *)
| deleteAll xs [] = [] (* when the second list is empty, it should return an empty list *)
| deleteAll (x::xs) (y::ys) = if(starts (x::xs) (y::ys))
then deleteAll (x::xs) (drop (length(x::xs)) (y::ys))
else y::(deleteAll (x::xs) ys);
The rest is good! After the change the answer should be correct : )
- deleteAll [1,2,3] [3,2,1,2,3,2,1,2,3];
val it = [3,2,2] : int list

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.