I am trying to take three lists of strings and have the code return a list interleaving the three. If the lists have unequal sizes then we use "-" to indicate a value is missing.
For example:
interleave3 ["1"; "2"; "3"] ["4"] ["5"; "6"]
should return:
["1"; "4"; "5"; "2"; "-"; "6"; "3"; "-"; "-"]
If the task had been to just interleave the elements until all the lists are empty it would have been fairly straightforward; just rotate the lists while appending one element at a time until they're all empty.
let rec interleave3 xs ys zs =
match xs, ys, zs with
| [], [], [] -> []
| [], ys, zs -> "-" :: interleave3 ys zs []
| x::xs, ys, zs -> x :: interleave3 ys zs xs
However, since the requirement is that each list should effectively be padded out to equal length, we need to somehow keep track of how long the longest list is, and continue padding the resulting list until very list has been padded out. One way of doing so is to keep a total count, and continue going even after we're done, until the total is divisible by 3, at which point we know the resulting list has an equal number of elements:
let interleave3 xs ys zs =
let rec aux xs ys zs n =
match xs, ys, zs with
| [], [], [] when n mod 3 = 0 -> []
| [], [], [] -> "-" :: aux [] [] [] (n+1)
| [], ys, zs -> "-" :: aux ys zs [] (n+1)
| x::xs, ys, zs -> x :: aux ys zs xs (n+1)
in aux xs ys zs 0
I would suggest to try with two lists,and then you go for 3 or more lists. Once you understand the pattern for two then you can extend the same concept for more lists. I have written a quick solution, but I don't claim it is idiomatic OCaml. Also list in OCaml is semicolon separated.
let rec patternMatching xs ys zs =
match xs, ys, zs with
| [], [], [] -> []
| x::xs, [], [] -> x :: "-" :: "-" :: patternMatching xs [] []
| [], y::ys, [] -> "-" :: y :: "-" :: patternMatching [] ys []
| [], [], z::zs -> "-" :: "-" :: z :: patternMatching [] [] zs
| x::xs, y::ys, [] -> x :: y :: "-" :: patternMatching xs ys []
| x::xs, [], z::zs -> x :: "-" :: z :: patternMatching xs [] zs
| [], y::ys, z::zs -> "-" :: y :: z :: patternMatching [] ys zs
| x::xs, y::ys, z::zs -> x :: y :: z :: patternMatching xs ys zs
# patternMatching ["1"; "2"; "3"] ["4"] ["5"; "6"];;
- : string list = ["1"; "4"; "5"; "2"; "-"; "6"; "3"; "-"; "-"]
Related
merge :: [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = x : y : merge xs ys
maxOfTwoLists [x] [y] = maximum (merge [x] [y])
I am trying to combine the two lists then find the max value in the single list. It compiles but when i call maxOfTwoLists it gives me a non-exhaustive patterns error. My merge returns a single list just fine, and maximum takes a single list. So it feels like it should be working.
If you're looking to merge two lists, the builtin concat would help. It flattens a list, so we could do the following:
maxOfTwoLists :: (Ord a) => [a] -> [a] -> a
maxOfTwoLists xs ys = maximum $ concat [xs,ys]
In which, $ means to evaluate the result of the right side function before applying it to the left side function.
As #badcook notes the pattern match isn't quite right.
merge :: [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = x : y : merge xs ys
maxOfTwoLists :: (Ord a) => [a] -> [a] -> a
maxOfTwoLists [] ys = maximum ys
maxOfTwoLists xs [] = maximum xs
maxOfTwoLists xs ys = maximum (merge xs ys)
I'll guess you wrote the merge function as an exercise but you can also use ++ from Prelude to append one list to another.
maxOfTwoLists :: (Ord a) => [a] -> [a] -> a
maxOfTwoLists xs ys = maximum (xs ++ ys)
Output:
λ> maxOfTwoLists [1,2,3] [4,5,6]
6
λ> maxOfTwoLists [1,2,3] []
3
λ> maxOfTwoLists [] [1,2,3]
3
λ>
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])
I need to write a function to merge two lists. Exactly like '++' is working.
let x = merge [1,2,3] [3,3,4] -- should output [1,2,3,3,3,4]
How should it be done?
Edit: solution is
merge :: [a] -> [a] -> [a]
merge [] ys = ys
merge (x:xs) ys = x : (merge xs ys)
Maybe something like this.
merge :: (a -> a -> Bool) -> [a] -> [a] -> [a]
merge pred xs [] = xs
merge pred [] ys = ys
merge pred (x:xs) (y:ys) =
case pred x y of
True -> x: merge pred xs (y:ys)
False -> y: merge pred (x:xs) ys
(++) xs ys = merge (\x y -> compare x y == LT) xs ys
Or, if you just need to repeat the functionality of (++), you can look up it's definition with hoogle which eventually leads you to the source code
(++) [] ys = ys
(++) (x:xs) ys = x : xs ++ ys
this is my assignment the string concatenation function is below and below that is the function that i need help with.
type Language = [String]
strcat :: String -> String -> String
strcat [] y = y
strcat (x:xs) y = x:(strcat xs y)
concat_lang :: Language -> Language -> Language
concat_lang [] y = y
concat_lang x [] = x
concat_lang (x:xs) (y:ys) = (strcat x y):(concat_lang (x:xs) ys)
This is my input to concat_lang : concat_lang ["a","b","c"] ["d","e","f"]
i want the output to be [ad,ae,af,bd,be,bf,cd,ce,cf]
Pls help!!
List comprehension makes life much easier
lang xs ys = [x:y:[] | x <- xs , y <- ys]
lang is polymorphic, if this is undesirable, simply add a type signature.
combinations :: [a] -> [b] -> [(a,b)]
combinations xs ys = concatMap (flip zip ys . repeat) xs
type Language = [String]
concat_lang :: Language -> Language -> Language
concat_lang xs ys = map f $ combinations xs ys
where
f (x,y) = x ++ y
use
concat_lang ["a","b","c"] ["d","e","f"]
to get
["ad","ae","af","bd","be","bf","cd","ce","cf"]
concat_lang xs ys = [ x++y | x <- xs, y <- ys]
Classic example where Applicative Functors can come in handy:
>> import Control.Applicative
>> (++) <$> ["a", "b", "c"] <*> ["d", "e", "f"]
["ad","ae","af","bd","be","bf","cd","ce","cf"]
>>
You should definitely check out Aplicative Functors for this ...
In SML, it's common and easy to define a function using both currying and pattern matching. Here's a simple example:
fun zip [] _ = []
| zip _ [] = []
| zip (x::xs) (y::ys) = (x,y)::(zip xs ys)
Ignoring library functions, what's the best way to port this to OCaml? As far as I can tell, there is no easy way to declare a function using both currying and pattern matching.
I would say it's best to just use a match expression.
let rec zip xs ys =
match xs, ys with
| [], _
| _, [] -> []
| x :: xs, y :: ys -> (x, y) :: zip xs ys
If you're set on not using match, it's a bit convoluted, but you can do this.
let rec zip = function
| [] -> (fun _ -> [])
| x :: xs ->
function
| [] -> []
| y :: ys -> (x, y) :: zip xs ys