So this is my question: i wanna make a function that takes a list and and int, it then recursively moves through the list, and if it finds an element in the list equal to the int, then it should return the entire list with the element removed, and a boolean indicating wether something was removed. this is what i got so far:
fun foo ([], n) = ([],false)
| foo ((x::xs), n) = if x = n
then (xs,true)
else ([x] # foo(xs,n),false);
my idea was to make the function cons the needed elements inside the tuple like this:
([x0] # [x1] # [x2] # [xs], true)
so is there any way to make this function? keep in mind that it has to stop once it hits the element equal to n, but still retain the rest of the list, and be able to return a boolean. run time is key.
Your current code is close to correct logically, but as you know it doesn't type-check because of [x] # foo (xs, n). foo returns a tuple, which can't be directly appended. Here's how to fix it:
fun foo ([], n) = ([], false)
| foo (x::xs, n) = if x = n
then (xs, true)
else let val (xs', tf) = foo (xs, n) in (x::xs', tf) end
The let is needed to extract the list from the tuple and find out if n was found in the tail of the list. Then we simply put the tuple back together with x consed back on to the front.
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
I was trying to implement k-out-of-N at SML so "pick(3,[1,2,3,4])" will return [[1,2,3],[1,3,4]...] (all the K-size picks out of N elements)
I used List.map which I figured it calls the function and apply it on each element.
Really can't figure out why when typing the input "pick(3,[1,2,3,4,5])" ,for example, it return an empty list.
My first thought was that it's because of the initial terms (choose (_,[]) = [])
But changing it didn't work as well.
The signature is ok (val pick = fn : int * 'a list -> 'a list list).
fun pick (_,[]) = []
| pick (0,_) = []
| pick (n,hd::tl) =
let
val with_hd = List.map (fn x => hd::x) (pick(n-1,tl))
val without_hd = pick(n,tl)
in
with_hd#without_hd
end;
The problem is related to your suspicion – the base cases are incorrect in that they always produce the empty list, and mapping fn x => hd::x onto the empty list produces the empty list.
Picking zero elements from anything should succeed, and produce the empty list.
That is, pick (0, _) = [[]] — a list with one element, which is the empty list.
You also need to rearrange the cases since pick(n, []) succeeds for n = 0 but not for any other n.
In summary,
fun pick (0, _) = [[]]
| pick (_, []) = []
with the rest of the function exactly as before.
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 very new to SML and I am trying a list exercise. The goal is sum up the previous numbers of a list and create a new list. For example, an input list [1, 4, 6, 9] would return [1, 5, 11, 20].
This is my solution so far, but I think the issue is with how I'm defining the function.
fun rec sum:int list -> int list =
if tl(list) = nil then
hd(list)
else
hd :: sum((hd(tail) + hd(tl(list)))::tl(tl(list)));
Besides that you are using rec as a function name, then you have some minor issues to work on.
The explicit type annotation you have made is treated as an annotation of the function result.
Thus, according to what you have written, then it should return a function and not the expected
list. This is clearly seen from the below example:
- fun rec_ sum : int list -> int list = raise Domain;
val rec_ = fn : 'a -> int list -> int list
Your should be careful of using the head and tail functions, when you don't do any checks on the
number of elements in the list. This could be done with either the length function, or (even
easier and often better) by pattern matching the number of elements.
Your code contains sum as a function call and tail as an variable. The variable tail has never
been defined, and using sum as a function call, makes me believe that you are actually using rec
as a keyword, but don't know what it means.
The keyword rec is used, when defining functions using the val keyword. In this case, rec is
needed to be able to define recursive functions (not a big surprise). In reality, the keyword fun
is syntactic sugar (a derived form) of val rec.
The following 3 are examples of how it could have been made:
The first is a simple, straight forward solution.
fun sumList1 (x::y::xs) = x :: sumList1 (x+y::xs)
| sumList1 xs = xs
This second example, uses a helper function, with an added argument (an accumulator). The list is constructed in the reverse order, to avoid using the slow append (#) operator. Thus we reverse the list before returning it:
fun sumList2 xs =
let
fun sumList' [] acc = rev acc
| sumList' [x] acc = rev (x::acc)
| sumList' (x :: y :: xs) acc = sumList' (y+x :: xs) (x :: acc)
in
sumList' xs []
end
The last example, show how small and easy it can be, if you use the standard list functions. Here the fold left is used, to go through all elements. Again note that the list is constructed in the reverse order, thus it is reversed as the last step:
fun sumList3 [] = []
| sumList3 (x::xs) = rev (foldl (fn (a, b) => hd b + a :: b) [x] xs)
try this -
fun recList ([], index, sum) = []
| recList (li, index, sum) =
if index=0 then
hd li :: recList (tl li, index+1, hd li)
else
sum + hd li :: recList (tl li, index+1, sum + hd li)
fun recSum li = recList (li, 0, 0)
In your case -
recSum([1,4,6,9]) ;
will give
val it = [1,5,11,20] : int list
also don't use rec as fun name -it keyword .
With a list of integers such as:
[1;2;3;4;5;6;7;8;9]
How can I create a list of list of ints from the above, with all new lists the same specified length?
For example, I need to go from:
[1;2;3;4;5;6;7;8;9] to [[1;2;3];[4;5;6];[7;8;9]]
with the number to split being 3?
Thanks for your time.
So what you actually want is a function of type
val split : int list -> int -> int list list
that takes a list of integers and a sub-list-size. How about one that is even more general?
val split : 'a list -> int -> 'a list list
Here comes the implementation:
let split xs size =
let (_, r, rs) =
(* fold over the list, keeping track of how many elements are still
missing in the current list (csize), the current list (ys) and
the result list (zss) *)
List.fold_left (fun (csize, ys, zss) elt ->
(* if target size is 0, add the current list to the target list and
start a new empty current list of target-size size *)
if csize = 0 then (size - 1, [elt], zss # [ys])
(* otherwise decrement the target size and append the current element
elt to the current list ys *)
else (csize - 1, ys # [elt], zss))
(* start the accumulator with target-size=size, an empty current list and
an empty target-list *)
(size, [], []) xs
in
(* add the "left-overs" to the back of the target-list *)
rs # [r]
Please let me know if you get extra points for this! ;)
The code you give is a way to remove a given number of elements from the front of a list. One way to proceed might be to leave this function as it is (maybe clean it up a little) and use an outer function to process the whole list. For this to work easily, your function might also want to return the remainder of the list (so the outer function can easily tell what still needs to be segmented).
It seems, though, that you want to solve the problem with a single function. If so, the main thing I see that's missing is an accumulator for the pieces you've already snipped off. And you also can't quit when you reach your count, you have to remember the piece you just snipped off, and then process the rest of the list the same way.
If I were solving this myself, I'd try to generalize the problem so that the recursive call could help out in all cases. Something that might work is to allow the first piece to be shorter than the rest. That way you can write it as a single function, with no accumulators
(just recursive calls).
I would probably do it this way:
let split lst n =
let rec parti n acc xs =
match xs with
| [] -> (List.rev acc, [])
| _::_ when n = 0 -> (List.rev acc, xs)
| x::xs -> parti (pred n) (x::acc) xs
in let rec concat acc = function
| [] -> List.rev acc
| xs -> let (part, rest) = parti n [] xs in concat (part::acc) rest
in concat [] lst
Note that we are being lenient if n doesn't divide List.length lst evenly.
Example:
split [1;2;3;4;5] 2 gives [[1;2];[3;4];[5]]
Final note: the code is very verbose because the OCaml standard lib is very bare bones :/ With a different lib I'm sure this could be made much more concise.
let rec split n xs =
let rec take k xs ys = match k, xs with
| 0, _ -> List.rev ys :: split n xs
| _, [] -> if ys = [] then [] else [ys]
| _, x::xs' -> take (k - 1) xs' (x::ys)
in take n xs []