Assume we use a list to represent number reversely, each node is a digit inside the number.
So [1;2;3;4;5] is the number 54321
Now we want to add up two such lists, e.g., adding [1;2] and [3;4], we get [4;6], which is the number 64.
here is my code:
let add l1 l2 =
let rec add_to up acc = function
| [] -> if up = 1 then 1::acc else acc
| hd::tl ->
let s = hd+up in
if s >= 10 then add_to 1 ((s-10)::acc) tl
else List.rev_append tl (s::acc)
and
add_up up acc = function
| [], [] -> if up = 1 then 1::acc else acc
| l, [] | [], l -> (add_to up [] l) # acc
| hd1::tl1, hd2::tl2 ->
let s = hd1+hd2+up in
if s >= 10 then add_up 1 ((s-10)::acc) (tl1, tl2)
else add_up 0 (s::acc) (tl1, tl2)
in
List.rev (add_up 0 [] (l1, l2))
The idea is very simple, just add two hds from two lists, and carry 1 to the next if the sum of two hds are bigger or equal with 10.
However, I think my code does not look beautiful.
we have the redundant part of the logic to solve the carry.
I have to do # on two lists.
Anyone can help me to make it more beautiful?
I think the trick is to generalize. The essence is to add three things, not two.
let sum a b =
let rec isum a b c =
match a, b with
| [], [] -> if c = 0 then [] else [c]
| [], x | x, [] -> isum [0] x c
| ah :: at, bh :: bt ->
let s = ah + bh + c in
(s mod 10) :: isum at bt (s / 10)
in
isum a b 0
This code isn't tail recursive. A tail recursive version will be a little less elegant.
Note: I assume you use [] to represent 0.
Related
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.
I have written a function:
let rec addAll f l =
match l with
| [] -> 0
| [x] -> x
| hd::tl -> let combined = addAll f tl in
f (hd) combined
;;
I works as titled, it will add all the elements of a list. However, I want to write this program so it is Left associative, so instead of combining the elements [1;2;3] as 1 - (2 - 3), I want it to be: (1 - 2) - 3.
Any hints on how I can make this forward recursive instead of tail? Or how can I make it so this function works as I intend? I know I could just reverse the list, but I want to try another way.
Your code does a right fold. Roughly speaking, it's like this:
let addAll f l = List.fold_right f l 0
You want to change it to a left fold. Roughly speaking you want this:
let addAll f l = List.fold_left f 0 l
Or, slightly more accurately you want:
let addAll f = function
| [] -> 0
| h :: t -> List.fold_left f h t
This second function does seem to do what you want:
# addAll (-) [1;2;3];;
- : int = -4
If you want to write it from scratch (not using List.fold_left), the easiest way is with an accumulator:
let addAllScratch f l =
let rec iadd f accum l =
match l with
| [] -> accum
| a::l -> iadd f (f accum a) l
in
match l with
| [] -> 0
| h :: t -> iadd f h t
This does do what you want:
# addAllScratch (-) [1;2;3];;
- : int = -4
(In essence, I just inserted the standard definition of List.fold_left into the code.)
let rec addAll f l =
match l with
| [] -> 0
| [x] -> x
| x::y::tl -> addAll f ((f x y)::tl)
;;
Test
# addAll (fun a b -> Printf.printf "(%d %d)" a b; a+b) [1;2;3];;
(1 2)(3 3)- : int = 6
I have a following problem. From a list, I must separate mod 3 = 0 element, mod 3 = 1 element and mod 3 = 2 element to 3 different lists and return list of these 3 lists. My question is pretty obvious - how do I do that? Is there some kind of simple rule to this I'm missing?
What I have so far is not much but there you go:
let separate xs =
let rec help xs i =
match xs i with
| [] _ -> []
| hd a -> if a mod 3 = 0 //HOW DO I RETURN
else if a mod 3 = 1
else
UPDATED:
Finished code:
let separate xs =
let rec help (list, i, xs1, xs2, xs3) =
match list with
| [] -> [xs1;xs2;xs3]
| head :: tail -> (if i mod 3 = 0 then help (tail, i+1, head::xs1, xs2, xs3)
else if i mod 3 = 1 then help (tail, i+1, xs1, head::xs2, xs3)
else help (tail, i+1, xs1, xs2, head::xs3))
in help (xs, 0, [], [], []);;
You'll need to accumulate the partial results in lists, and then return those lists :
let split_by_mod_3 l =
let rec aux l mod0 mod1 mod2 = match l with
| [] -> [mod0; mod1; mod2]
| hd::tail when hd mod 3 == 0 -> aux tail (hd::mod0) mod1 mod2
| hd::tail when hd mod 3 == 1 -> aux tail mod0 (hd::mod1) mod2
| hd::tail when hd mod 3 == 2 -> aux tail mod0 mod1 (hd::mod2)
in
aux l [] [] [];;
A usual way is to use List.fold* function, that generalizes an idea of list iteration. But, in your case, it may not be appropriate (depending on what your teachers are asking).
You can iterate over your list maintaining some notion of state (indeed, you need three extra "variables" for three different lists). Here is a pattern for iterating over lists
let my_function lst =
let rec loop acc lst = match lst with
| [] -> <do_some_post_iteration_work> acc
| head :: rest ->
let result = <do_something_with_nth_element> head in
let accum = <add_result_to_accumulator> result acc in
loop accum rest in
let accum = <initialize_accumulator> in
loop accum lst
I used long names so that you can understand the meaning without extra comments, although you're welcome to ask. Also, keep in mind, that your state (aka accumulator), can be also a value of any type. Using a triple would be a not a bad idea in your case.
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.
I want to write a function rotate n l that returns a new list containing the same elements as l, "rotated" n times to the right. For example,
rotate 0 [1;2;3;4] should return [1;2;3;4]
rotate 1 [1;2;3;4] should return [4;1;2;3]
rotate 2 [1;2;3;4] should return [3;4;1;2]
rotate 3 [1;2;3;4] should return [2;3;4;1]
rotate 4 [1;2;3;4] should return [1;2;3;4]
etc.
The behavior of rotate n for n less than 0 should be the same as for n equal to 0.
I want to write this without using the list concatenation operator # from Pervasives.
Update: Here is the rotation function I wrote:
let rot1 l =
let rec iterate acc = function
[] -> []
| [x] -> x :: List.rev acc
| x :: l -> iterate (x :: acc) l
in
iterate [] l;;
But I want it to do the same thing without using List.rev.
Is there a way to do this?
Agree with Jeffrey, show us what you tried. Here's a small hint in case you need to get started. If you can write a function that performs only 1 rotation i.e. equivalent to rotate 1 l. (I call it one_rot). Then rotate can be easily defined as:
let rec rotate n l =
match n with
| 0 -> l
| _ -> rotate (n-1) (one_rot l)
Your solution is perfectly fine for me. Not sure what you have against List.rev but here's a completely stand alone one_rot. Note that we have to sacrifice tail recursion. You could probably make this quite a bit shorter too:
let rec last = function
| [] -> assert false
| [x] -> x
| x::xs -> last xs
let rec init = function
| [] -> []
| [x] -> []
| x::xs -> x::(init xs)
let one_rot l = (last l)::(init l)
This problem can be solved by combining these 3 functions:
cat(skip(list, places), take(list, places))
The implementation looks like:
let rec cat = function
([], y) -> y
| (x::xs, y) -> x :: cat (xs, y)
let rec skip = function
([], _) -> []
| (_::xs as xs1, c) -> if c > 0 then skip(xs, c - 1) else xs1
let rec take = function
([], _) -> []
| (x::xs, c) -> if c > 0 then x :: take(xs, c - 1) else []
let cycle l i =
cat (skip (l, i), take (l, i))
cycle ([1;2;3;4;5;6], 3);;
val it : int list = [4; 5; 6; 1; 2; 3]