Good morning,
I have a problem with coding using ocaml so I had to code a function that take on input list then add to this list an element.
But using this does'nt affect the list1 so how can I do this ?
Thank you.
let rec append list1 element list2 = match list2 with
[]-> list1
| e::l -> if ( element = e ) then e :: list1
else (append list1 element l)
;;
List are immutable in OCaml, you can't change this. You can write a function append that takes a list and returns a new list that appends an element to it.
For example, here is the prepend function that takes a list and an element and returns a new list with the given element prepended to the passed list,
let prepend xs x = x :: xs
The append function is a little bit trickier, since lists in OCaml are singly-linked, so it is easy to prepend but hard to append. To implement the append function you need an intermediate list, let's call it acc for accumulator. You then go through each element of the input list and add it to the accumulator. Since you're prepending, then once the input list is over your accumulator will have all the elements of the input list by in the reversed order, i.e., the first element (aka the head) of the acc list will be the last element of the input list. Now you what is left is to prepend the element that we want to append to the reversed acc list and reverse act. Here is the skeleton code for you
let append xs x =
let rec loop xs acc = match xs with
| ... -> ... in
loop xs []
Related
I am trying to insert a number x into a sorted list l using Ocaml's List.fold_right and return the list with the inserted element. I have figured out a way to insert it if the element is to go at the front of the list or in the middle of the list, however I cannot figure out how to code the case where the element is larger than every element in the list and thus must go at the end.
Here is what I have so far:
let insert_number (x: int) (l: int list): int list =
List.fold_right l ~f:(
fun cur -> fun acc ->
if x < cur then cur::x::accum
else cur::accum
) ~init: []
Using this with a test case like:
insert_number (3) ([1; 2; 4]);;
- : int list = [1; 2; 3; 4]
gives the correct answer. However, with a test case like this:
insert_number (3) ([1; 2]);;
- : int list = [1; 2]
the number is not inserted because it should be added to the end of the list.
Could someone help me understand how I am supposed to integrate this case into the function used with List.fold_right.
A fold works by passing along a set of state as it iterates over each element in a list (or other foldable data structure). The function passed in takes both the current element and that state.
I think you're really really close, but you need as Jeffrey suggests a boolean flag to indicate whether or not the value has been inserted. This will prevent multiple insertions and if the flag is still false when the fold is done, we can detect that and add the value to insert.
This match also serves the purpose of giving us an opportunity to discard the no longer needed boolean flag.
let insert v lst =
match List.fold_right
(fun x (inserted, acc) ->
if v > x && not inserted then (true, x::v::acc)
else (inserted, x::acc))
lst
(false, []) with
| (true, lst) -> lst
| (_, lst) -> v::lst
One way to look at List.fold_right is that it looks at each element of the list in turn, but in reverse order. For each element it transforms the current accumulated result to a new one.
Thinking backward from the end of the list, what you want to do, in essence, is look for the first element of the list that's less than x, then insert x at that point.
So the core of the code might look something like this:
if element < x then element :: x :: accum else element :: accum
However, all the earlier elements of the list will also be less than x. So (it seems to me) you need to keep track of whether you've inserted x into the list or not. This makes the accumulated state a little more complicated.
I coded this up and it works for me after fixing up the case where x goes at the front of the list.
Perhaps there is a simpler way to get it to work, but I couldn't come up with one.
As I alluded to in a comment, it's possible to avoid the extra state and post-processing by always inserting the element and effectively doing a "local sort" of the last two elements:
let insert_number x l =
List.fold_right (
fun cur -> function
| [] when x > cur -> [cur; x]
| [] -> [x; cur]
| x::rest when x > cur -> cur::x::rest
| x::rest -> x::cur::rest
) l []
Also, since folding doesn't seem to actually be a requirement, here's a version using simple recursion instead, which I think is far more comprehensible:
let rec insert_number x = function
| [] -> [x]
| cur::rest when cur > x -> x::cur::rest
| cur::rest -> cur::insert_number x rest
Running insert ls n should return a list of piles from taking ls and inserting n so that either n has been added to the head of the first pile in ls whose previous head is greater than or equal to n, or if it doesn't exist, a new pile containing just n is added to the end of ls.
For example,
insert [[4]; [5]] 3 = [[3;4]; [5]]
insert [[2]; [6]] 4 = [[2]; [4;6]]
insert [[3]] 4 = [[3]; [4]]
Basically, I'm trying to use the sort helper function that appends to the list if the element is less than the first in the list, and then in that case to just return the rest of the list.
let rec insert ls n =
match n with
| [] -> [x]
| y::ys -> if x < y then x::y::ys else y::insert x ys;;
let rec sort n =
match n with
| [] -> []
| x::xs -> insert x (sort xs);;
You keep confusing the order and type of arguments in your insert function. In your text description and following from the examples section, insert has type 'a list list -> 'a -> 'a list list, but when you try to write your insert function, you match the element n with a list. In the same manner, when you call insert from sort you pass the element as the first argument.
Next, your insert function shall return a list of lists, but in the first branch of your match, [] -> [x], you return just a list. In addition, there is no x variable bound in this match or anywhere else, probably you meant n?
Finally, when you compare the first element of the input list with the element n you compare the whole pile, instead of the head of the pile.
So let's try to rectify these problems, first of all, we have to match on ls instead of n,
let rec insert ls n =
match ls with
(* ^^
ls not n! *)
Next, if we have an empty input, then we need to return a list containing a single pile, where a pile is a list itself,
| [] -> [[n]] (* a list containing a list with a single element `n` *)
Finally, when we match on the head of the input list, we have to keep in mind that the head is the list itself, i.e., a pile, so we need to unpack it as well,
| (x::xs)::ys ->
(* ^^^^^^^
here x is the head of the pile, and x::xs is the whole pile *)
and pack it back,
if n < x then (n::x::xs)::ys else (x::xs)::insert ys n
(* ^^^^^^^^^^ ^^^^^^^
extended pile intact pile *)
The next step would be to make the match complete, i.e., to think what to do when the pile is empty itself (could it be?) and what to do when x is equal to n.
I'm new to F# and I'm trying to write a method split that splits a list into 2 pieces. It takes a tuple with the first element being the number of elements to split and the second element is the list . For example, split (2, [1;2;3;4;5;6]) should return ([1;2], [3;4;5;6]),
This is what I have so far, but for some reason it is returning the second element of the tuple as the original list without the head. I don't understand this because I thought that x::xs automatically makes x the head element and xs the rest of the list, which would mean that each recursive call is taking the tail of the previous list and chopping off the first term.
let rec split = function
|(n, []) -> ([], [])
|(0, xs) -> ([], xs)
|(n, x::xs) -> let temp = x :: fst (split(n-1, xs))
(temp, xs);;
The problem is on this line:
(temp,xs);;
here in your example, xs will always be [2;3;4;5;6] as long as n>0
You need to get the second element of the list with something like
|(n,x::xs) ->
let a,b = split (n-1,xs)
(x::a,b)
I'm having trouble with the following exercise :
I'm supposed to reverse all elements in a list except for the first one, the first element of the list must stay in its original position.
Correct Example:
input: rvrsTail [1,2,3,4,5]
output [1,5,4,3,2]
What I have done so far:
rvrsTail :: [x] -> [x]
rvrsTail xs = reverse ( tail xs)
This does reverse the the tail of the list but removes the first element, and since I can't store the first element in a variable I can't seem to understand how to solve this issue.
Erroneous Output:
input: rvrsTail [1,2,3,4,5]
output [5,4,3,2]
Since this is supposed to be a beginner's exercise, the solution should be simple.
When you receive a non-empty list, you must leave the head where it is and append the tail reversed. In other words, you can deconstruct the list into the head and the tail, then reconstruct the list with that head and the reversed tail:
rvrsTail :: [x] -> [x]
rvrsTail [] = []
rvrsTail (listHead : listTail) = listHead : reverse listTail
You are almost there. For making sure that the first element of the list stays as it is, just use pattern matching and remove the tail call:
rvrsTail :: [x] -> [x]
rvrsTail (x:xs) = x:(reverse xs)
Now, note that the above function will throw an exception when tried with empty list. You should handle that case.
The function needs to take an ordered list of integer elements and return all the combinations of adjacent elements in the original list. e.g [1,2,3] would return [[1,2,3],[1],[1,2],[2],[2,3],[3]].
Note that [1,3] should not be included, as 1 and 3 are not adjacent in the original list.
Apart from the fact that inits and tails aren't found in Prelude, you can define your function as such:
yourFunction :: [a] -> [[a]]
yourFunction = filter (not . null) . concat . map inits . tails
This is what it does, step by step:
tails gives all versions of a list with zero or more starting elements removed: tails [1,2,3] == [[1,2,3],[2,3],[3],[]]
map inits applies inits to every list given by tails, and does exactly the opposite: it gives all versions of a list with zero or more ending elements removed: inits [1,2,3] == [[],[1],[1,2],[1,2,3]]
I hope you already know concat: it applies (++) where you see (:) in a list: concat [[1,2],[3],[],[4]] == [1,2,3,4]. You need this, because after map inits . tails, you end up with a list of lists of lists, while you want a list of lists.
filter (not . null) removes the empty lists from the result. There will be more than one (unless you use the function on the empty list).
You could also use concatMap inits instead of concat . map inits, which does exactly the same thing. It usually also performs better.
Edit: you can define this with Prelude-only functions as such:
yourFunction = concatMap inits . tails
where inits = takeWhile (not . null) . iterate init
tails = takeWhile (not . null) . iterate tail
So, if you need consecutive and non empty answers (as you've noticed in comment).
At first, let's define a simple sublist function.
sublist' [] = [[]]
sublist' (x:xs) = sublist' xs ++ map (x:) (sublist' xs)
It returns all sublists with empty and non-consecutive lists. So we need to filtering elements of that list. Something like sublists = (filter consecutive) . filter (/= []) . sublist'
To check list for it's consecution we need to get pairs of neighbors (compactByN 2) and check them.
compactByN :: Int -> [a] -> [[a]]
compactByN _ [] = [[]]
compactByN n list | length list == n = [list]
compactByN n list#(x:xs)= take n list : compactByN n xs
And finally
consecutive :: [Int] -> Bool
consecutive [_] = True
consecutive x = all (\[x,y] -> (x + 1 == y)) $ compact_by_n 2 x
And we have
λ> sublists [1,2,3]
[[3],[2],[2,3],[1],[1,2],[1,2,3]]
Done. http://hpaste.org/53965
Unless, I'm mistaken, you're just asking for the superset of the numbers.
The code is fairly self explanatory - our superset is recursively built by building the superset of the tail twice, once with our current head in it, and once without, and then combining them together and with a list containing our head.
superset xs = []:(superset' xs) -- remember the empty list
superset' (x:xs) = [x]:(map (x:) (superset' xs)) ++ superset' xs
superset' [] = []