In Ocaml language the goal was to combine(append) two lists while removing the duplicates.
let rec find_dup a lst =
match lst with
| [] -> false
| hd::tl -> if (hd == a) then true else find_dup a tl;;
let rec app lst2 lst1 =
match lst1 with
| [] -> lst2
| hd::tl -> if (find_dup hd lst2) then (app tl lst2)
else hd::app tl lst2
;;
I have my code like this but when the test case is
app [4;5;6;7] [1;2;3;4] the answer should be [1;2;3;4;5;6;7]
but I keep getting
: int list = [1; 2; 5; 3; 6; 4; 7]
What is going on?
You're switching the lists around for every recursive call.
Look at the argument order of the function definition:
let rec app lst2 lst1
and then the recursive function call:
app tl lst2
Also, just to nitpick, find_dup already exists in the standard library. It's called List.mem.
Related
So far, I've made a function which matches all elements of one list with only the first element of another list, but I need it to match all elements of list 1 with all elements of list 2.
My code so far looks like this:
let prototype (lst1: 'a list) (lst2: 'b list) =
List.map (fun i -> [i,lst2.Head]) lst1 |> List.concat
So you figured out how to pair all elements of lst1 with a single thing. Great!
Now look: inside the map's parameter, you have the exact same problem - pair every element of lst2 with i. So you can just solve it the exact same way:
let prototype (lst1: 'a list) (lst2: 'b list) =
List.map (fun i -> List.map (fun j -> [i, j]) lst2 |> List.concat) lst1 |> List.concat
But this is a bit ugly of course. There are a few minor modifications you can make to make it prettier.
First, note that List.map >> List.concat is equivalent to List.collect:
let prototype (lst1: 'a list) (lst2: 'b list) =
List.collect (fun i -> List.collect (fun j -> [i, j]) lst2) lst1
But of course a much better option is to use list comprehensions:
let prototype (lst1: 'a list) (lst2: 'b list) =
[ for i in lst1 do
for j in lst2 ->
i, j
]
I have this series of functions, isMember, addElem and countries:
let rec isMember x = function
| y::ys -> y=x || (isMember x ys)
| [] -> false
let addElem x ys = if isMember x ys then ys else x::ys
let rec countries = function
| [] -> []
| (c1,c2)::m -> addElem c1 (addElem c2 (countries m))
I want to rewrite countries using higher-order functions, but I'm not entirely sure how to:
My guess would be it having something to do with List.map, as I'm applying a function to each element of the list.
let countriesHigherOrder m =
List.map (fun x -> addElem x m)
Instead of using List.map, you can use List.fold with an accu that you initialize to [] and add elements to accu.
let countriesHigherOrder m =
List.fold (fun acc (c1,c2) -> addElem c1 (addElem c2 acc)) [] m
or by defining addPair:
let addPair (x, y) ys =
addElem x (addElem y ys)
let countriesHigherOrder m =
List.fold (fun acc (c1,c2) -> addPair (c1, c2) acc) [] m
If you want to flatten a list of pairs into a simple list and at the same time, preserve only one occurence of identical elements, the shortest code will involve the append operator.
let countries' m =
List.unzip m ||> (#)
|> Seq.distinct
|> Seq.toList
If, on the other hand, you need the peculiar order of your doubly recursive approach, you can convert the list of tuples into two-element lists and concatenate those.
let countries'' m =
List.rev m
|> List.collect(fun (x,y) -> [y;x])
|> Seq.distinct
|> Seq.toList
|> List.rev
I'm trying to make an example function tail recursive.
Here is the original function:
let rec s xs ys =
match (xs, ys) with
|([],[]) -> []
|(xs, []) -> xs
|([], ys) -> ys
|(x::xs,y::ys) -> x::y::s xs ys
Below is my attempt to make it tail recursive:
let sC xs ys =
let rec sCTR xs ys acc =
match (xs, ys) with
|([],[]) -> acc
|(xs, []) -> acc#xs
|([], ys) -> acc#ys
|(x::xs,y::ys) -> sCTR xs ys acc#[x]#[y]
sCTR xs ys []
My issue is, however, that the order of the items are all wrong.
When I input the lists [1;2;3;] [7;8;] in the first function I get the result [1; 7; 2; 8; 3]
But when I input [1;2;3;] [7;8;] in the second function I get [3; 2; 8; 1; 7]
Why is the order wrong? I thought that list1#list2 would result in a new list with the order of list1 elements first and then list2 elements
You've just assumed the wrong precedence for #; what you've got is interpreted as
(sCTR xs ys acc)#[x]#[y]
but what you want is
sCTR xs ys (acc#[x]#[y])
fun flat [] = []
| flat (l::ls) = l # flat ls;
This will flatten a list.
Is there a way to non recursively do the same operation? Perhaps with HOFs?
You could use high-order function List.foldr:
fun flat xs = List.foldr (fn (x, acc) => x # acc) [] xs
As #Andreas said, the function above can be shortened:
fun flat xs = List.foldr op# [] xs
Although you would like to implement flat as an exercise, List.concat in the standard library does exactly the same thing.
Hi guys I'm implementing an F# function that takes two lists of type : (int*float) list. These two lists have different lentgths.
The int element of the couple is an increasing code.
What I wanted to do is create a new list that will contain a couple (int*float) for each two elements of the two lists that have the same code. It's important to note that codes in lists are in increasing order.
These lists are probably a little long, like 2-3000 elements., so I tried to implement this function using continuation passing style in order to avoid StackOverflowExceptions. but sadly i failed.
This is the function, i hope you will give me any hints!
let identifiedDifference list1 list2 =
let rec produceResult (l1, l2) k =
match l1,l2 with
| [],[]
| _,[]
| [],_ -> k []
| (code,rate:float)::xs, (code2,rate2)::ys ->
if code = code2
then
produceResult (xs, ys) (fun c -> (code,Math.Abs(rate-rate2))::(k c))
elif code > code2
then produceResult (l1, ys) k
else produceResult (xs, l2) k
produceResult (list1, list2) id
I've done something wrong?
(fun c -> (code,Math.Abs(rate-rate2))::(k c))
should be
(fun c -> k ((code,Math.Abs(rate-rate2))::c))
to make it tail-recursive:
let identifiedDifference list1 list2 =
let rec produceResult (l1, l2) k =
match l1,l2 with
| [],[]
| _,[]
| [],_ -> k []
| (code,rate:float)::xs, (code2,rate2)::ys ->
if code = code2 then produceResult (xs, ys) (fun c -> k ((code,Math.Abs(rate-rate2))::c))
elif code > code2 then produceResult (l1, ys) k
else produceResult (xs, l2) k
produceResult (list1, list2) id
This will also fix your results being returned in reverse order.
The problem lies in this line
produceResult (xs, ys) (fun c -> (code,Math.Abs(rate-rate2))::(k c))
Here you invoke continuation but this call is not tail because you still need to cons (code,Math.Abs(rate-rate2)) to the result of (k c)
I guess you can build result list from the inside out and just reverse final result:
let identifiedDifference list1 list2 =
let rec produceResult (l1, l2) k =
match l1,l2 with
| [],[]
| _,[]
| [],_ -> k []
| (code,rate:float)::xs, (code2,rate2)::ys ->
if code = code2
then
produceResult (xs, ys) (fun c -> k((code,Math.Abs(rate-rate2))::c))
elif code > code2
then produceResult (l1, ys) k
else produceResult (xs, l2) k
produceResult (list1, list2) List.rev
EDIT:
after second look I think CPS is not needed here and using accumulator should do the trick:
let identifiedDifference list1 list2 =
let rec run l1 l2 acc =
match l1, l2 with
| [], _ | _, [] -> List.rev acc
| (code1, rate1 : float)::xs, (code2, rate2)::ys ->
if code1 = code2 then
run xs ys ((code1, abs (rate1 - rate2))::acc)
elif code1 > code2 then
run l1 ys acc
else
run xs l2 acc
run list1 list2 []
For an alternative answer, take a look at this: http://fssnip.net/75
The function takes a couple of sequences and returns pairs which match according to some matching function. I haven't volume-tested it.
The function is actually used in the larger snippet here: http://fssnip.net/76