"deleteAll" method only removes one occurrence - list

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

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

Represent a nil list and/or a list(nil)

Background
We are implementing this algorithm in F#.
Here is a little bit more information from Topor (1982) about the notation that the algorithm uses:
Formally, a 't list is either null (denoted nil) or has a hd (which is a 't) and a tl (which is a 't list)... If x is a list, we test whether it is null by writing null x... We create a new list, adding the element a at the front of an existing list x, by writing a:x... We denote the unit list containing the element a by list(a)... list(x) = x:nil.
Question
What we're wondering is how in F# to express those nil, null, and list(nil) values. For instance, should we be using the Option type, an empty list, or something else?
What We Have Tried
let rec kpermute k (xs: 't list) =
let rec mapPerm k xs ys =
match ys with
| [] -> []
| head::tail ->
let kpermuteNext = kpermute (k-1) (removeFirst head xs)
let mapPermNext = mapPerm k xs tail
mapcons head kpermuteNext mapPermNext
match k with
| 0 -> [[]]
| _ when xs.Length < k -> []
| _ -> mapPerm k xs xs
When working with lists, for list(nil) we use [[]] and for nil we use []. While that's fine, there might be a more expressive way to do it. There are also times when we use List.empty<'t list> and List.empty<'t> when the type inference needs more information.
The paper gives you all the answers: nil is []; null x is a test for whether x is the empty list; list(nil) is [[]].
The naïve translation of algorithm B to F# is as follows:
let rec minus a = function
| [] -> failwith "empty list"
| xh :: xt -> if xh = a then xt else xh :: minus a xt
let rec permute2 k x =
if k = 0 then [[]]
elif List.length x < k then []
else mapperm k x x
and mapperm k x = function
| [] -> []
| yh :: yt -> mapcons yh (permute2 (minus yh x)) (mapperm x yt)
and mapcons a ps qs =
match ps with
| [] -> qs
| ph :: pt -> a :: ph :: mapcons a pt qs

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.

F# Recursive Functions: make list items unique

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.

Returning the list of elements occurring in just one list - SML

If L1 = [1,2,3,4,5] and L2 [4,5,6,7,8], I want to return [1,2,3,5,7,8] which are the elements occurring in one list only. I already wrote a function returning the list of items occurring in both lists.
fun exists x nil = false | exists x (h::t) = (x = h) orelse (exists x t);
fun listAnd _ [] = []
| listAnd [] _ = []
| listAnd (x::xs) ys = if exists x ys then x::(listAnd xs ys)
else listAnd xs ys
The list I am looking for should be given by L1#L2 - (ListAnd L1 L2). I also found functions that delete an element and remove Duplicates. I made several attempts at changing the remDup function slightly so that it will leave no trace of ANY items that occured more than once. Could not get it working. I am not sure how to use and combine all those functions to make it work.
fun delete A nil = nil
| delete A (B::R) = if (A=B) then (delete A R) else (B::(delete A R));
fun remDups nil = nil
| remDups (A::R) = (A::(remDups (delete A R)));
If there is a diff function where diff xs ys returns all elements in xs but not in ys, you can implement listOr function easily:
fun listOr xs ys = diff (xs#ys) (listAnd xs ys)
The diff function can be written similarly to listAnd:
fun diff xs [] = xs
| diff [] _ = []
| diff (x::xs) ys = if exists x ys
then diff xs ys
else x::(diff xs ys)