Given a list of tuples,
[(1,2),(3,4),(5,6)]
I need to unzip it to look like this
[[1,3,5],[2,4,6]]
unzip needs to be of type ('a * 'a) list -> 'a list list.
So far, I have this as my unzip function but my input is incorrect, and I am not sure how to access pass through ('a * 'a).
val rec last =
fn (h::nil) => h
|(h::list) => last (list)
| (nil) => raise Empty;
fun unzip [] = []
| unzip L = [(map hd L), (map last L)];
this returns 'a list list -> 'a list list
You were given a list of tuples
[(1,2),(3,4),(5,6)]
And we want to create a function to re-organize them into
[[1,3,5],[2,4,6]]
We know the output should look something like:
[ [tuple heads], [tuple tails] ]
And we know map gives us an output of list, which is the datatype we are looking for.
Thus,
fun unzip L = [ (map f1 L), (map f2 L) ]
I recognize this as a homework problem, so I will leave it there for you to think about the appropriate function for map. Think about how tuple behave and how do you manipulate data inside a tuple. Remember that f1 should be different from f2 as the two manipulate different things.
Go Cougs!
You can also unzip using foldr in the following way:
val unzip = foldr (fn ((x,y), (xs, ys)) = (x::xs, y::ys)) ([], [])
Related
I have created a working solution for concat, but I feel that I can reduce this using List.fold_lift.
Here is my current code:
let rec concat (lists : 'a list list) : 'a list =
match lists with
| [] -> []
| hd :: tl -> hd # concat tl ;;
Here is what I have tried:
let concat (lists : 'a list list) : 'a list =
List.fold_left # lists ;;
This gives me the error: This expression has type 'a list list but an expression was expected of type
'a list
I think this is because the return value of list.fold_left gives us a list, but we are feeding it a list of lists so it then returns a list of lists again. How can I get around this without matching?
I was also playing around with List.map but with no luck so far:
let concat (lists : 'a list list) : 'a list =
List.map (fun x -> List.fold_left # x) lists ;;
Consider the type signature of List.fold_left:
('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
List.fold_left takes three arguments.
A function.
An initial value.
A list to iterate over.
List.fold_left # lists
You're making two mistakes.
First off, this parses as (List.fold_left) # (lists).
You're looking for List.fold_left (#) lists. But that's still not quite right, because...
You're only passing two arguments, with lists being the initial value, while List.fold_left expects three.
I think that you're looking for something like:
let concat lists = List.fold_left (#) [] lists
Demonstrated:
utop # let concat lists = List.fold_left (#) [] lists in
concat [[1;2;3]; [4;5;6]; [7;8;9]];;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]
It is possible to write concat as fold_left while avoiding quadractic complexity by switching temporarily to different representation of list
If I have a list l, I can easily lift into an append function:
let to_append l = fun new_list -> l # new_list
I can also get back a list from an append function with
let to_list append = append []
And since for any list l, I have to_list ## to_append l = l, this means that the to_append is one-to-one: it does not lose any information.
Moreover concatenating two appends functions is exactly function composition
let append_concat f g l = f (g l)
Since we are not building yet any concrete list, append_concat has a constant cost (we are delaying the time complexity to the moment where we will call the append function).
We can use this better behavior of append_concat to write a linear concat' function that maps a list of lists to an append function:
let concat' l =
List.fold_left
(fun append l -> append_concat append (to_append l))
(to_append [] (* aka Fun.id *))
l
Note that this concat' is not yet building a list, it is building a closure which records the list of append functions to call later.
Building concat from concat' is then a matter of transforming back my append function to a list:
let concat l = to_list (concat' l)
And it is the call of to_list which will have a time complexity equal to the size of the final list.
To check that we got the right complexity, we can test that flattening the following list
let test =
List.init 1_000_000
(fun i ->
List.init 4 (fun k -> k + 4 * i)
)
(* this is [[0;1;2;3]; [4;5;6;7]; ... [...; 3_999_999]] *)
with
let flattened = concat test
is nearly instant.
I have this list of tuples
[(4,'a'), (1,'b'), (2,'c'), (2,'a'), (1,'d'), (4,'e')]
I want to get the first elements of every tuple then replicate it to make the following: "aaaabccaadeeee"
I came up with this code, but it only gives me the replicate of the first tuple.
replicate (fst ( head [(4,'a'), (1,'b')])) ( snd ( head [(4,'a'), (1,'b')]))
--output is: "aaaa"
I was thinking to use map for to get the replicate of every tuple, but I didn't succeed.
Since you already know how to find the correct answer for a single element, all you need is a little recursion
func :: [(Int, a)] -> [a]
func [] = []
func ((n, elem):rest) = (replicate n elem) ++ (func rest)
Mapping the values should also work. You just need to concatenate the resulting strings into one.
func :: [(Int, a)] -> [a]
func xs = concat $ map func2 xs where
func2 (n, elem) = replicate n elem
Or, if you are familiar with currying:
func :: [(Int, a)] -> [a]
func xs = concat $ map (uncurry replicate) xs
Finally, if you are comfortable using function composition, the definition becomes:
func :: [(Int, a)] -> [a]
func = concat . map (uncurry replicate)
Using concat and map is so common, there is a function to do just that. It's concatMap.
func :: [(Int, a)] -> [a]
func = concatMap (uncurry replicate)
Let
ls = [(4,'a'), (1,'b'), (2,'c'), (2,'a'), (1,'d'), (4,'e')]
in
concat [replicate i x | (i, x) <- ls]
will give
"aaaabccaadeeee"
The point-free version
concat . map (uncurry replicate)
You are correct about trying to use map. But first lets see why your code did not work
replicate (fst ( head [(4,'a'), (1,'b')])) ( snd ( head [(4,'a'), (1,'b')]))
Your first parameter to replicate is the head of your list which is (4, 'a'). Then you are calling fst on this, thus the first parameter is 4. Same things happens with second parameter and you get 'a'. The result of which you see.
Before using map lets try to do this with recursion. You want to take one element of list and apply replicate to it and then combine it with the result of applying replicate on the second element.
generate [] = []
generate (x:xs) = replicate (fst x) (snd x) ++ generate xs
Do note I am using pattern matching to get the first element of list. You can us the pattern matching to get the element inside the tuple as well, and then you would not need to use the fst/snd functions. Also note I am using pattern matching to define the base case of empty list.
generate [] = []
generate ((x,y):xs) = replicate x y ++ generate xs
Now coming to map, so map will apply your function to every element of the list, here's the first try
generate (x,y) = replicate x y
map generate xs
The result of the above will be slightly different from recursion. Think about it, map is going to apply generate to every element and store the result in a list. generate creates a list. So when you apply map you are creating a list of list. You can use concat to flatten it if you want, which will give you the same result as recursion.
Last thing, if you can use recursion, then you can use fold as well. Fold will just apply a function to every element of the list and return the accumulated results (broadly speaking).
--first parameter is the function to apply, second is the accumulator, third is your list
foldr step [] xs
where step (x,y) acc =
(replicate x y) ++ acc
Again here I have used pattern matching in the function step to extract the elements of the tuple out.
I'm trying to map a list of tuples into a different list of tuples with no luck.
Example input:
a = [("eo","th"),("or","he")]
Example output:
[('e','t'),('o','h'),('o','h'),('r','e')]
I have tried:
map (\(a,b) -> (a!!0,b!!0):(a!!1,b!!1):[]) a
but it produces:
[[('e','t'),('o','h')],[('o','h'),('r','e')]]
You have to use concat on your result or use concatMap instead of map. After all, you return lists in your map and therefore get a list of lists.
Let's give your function a name and a type:
magic :: [([Char], [Char])] -> [(Char, Char)]
Now, we can think of this as a two-step process: from every pair in the original list we're going to get a list:
magicPair :: ([Char], [Char]) -> [(Char, Char)]
magicPair (a,b) = zip a b
Now we need to map magicPair over all elements in your original list and concatenate the result:
magic xs = concat (map magicPair xs)
The combination concat . map f is so common that there is a function called concatMap for this:
magic xs = concatMap magicPair xs
And using a function f on a pair instead of two arguments is also common, so magicPair = uncurry zip:
magic xs = concatMap (uncurry zip) xs
We can now remove xs on both sides to end up with the final variant of magic:
magic = concatMap (uncurry zip)
Here is a quick way to give you the output
simplify = (>>= uncurry zip)
I need a function in OCaml that will take a type of
('a list * b' list) list and make of it
'a list * b' list. I have tried with the built in functions List.flatten and List.concat but they do not work, they require a type of 'c list list. Can someone help me?
You have to use the functions List.split and List.flatten:
let my_function l =
let (fst_list, snd_list) = List.split l in
List.flatten fst_list, List.flatten snd_list ;;
First the split function will generate and 'a list list and a 'b list list, then you just have to flatten them.
You can do it using the function fold_left like this :
You start with two empty lists working as accumulators. For every sub-lists in your the input list, you add the elements into the respective accumulator (elements of the first sub-list in the first accumulator and same thing for the second sub-list).
# let flatten l =
let (l1,l2) =
List.fold_left (fun (l1,l2) (x,y) ->
(x :: l1, y :: l2)) ([], []) l in
List.rev (List.flatten l1), List.rev (List.flatten l2);;
val flatten : ('a list * 'b list) list -> 'a list * 'b list = <fun>
#
Unfortunately there is no map for tuples and you need to decompose - e.g. using using split and flatten:
let splcat x = match List.split x with | (a,b) -> (List.flatten a, List.flatten b) ;;
That's how it looks on the commandline:
utop # splcat [([1;2],["a"]); ([3],["uvw";"xyz"]) ] ;;
- : int list * bytes list = ([1; 2; 3], ["a"; "uvw"; "xyz"])
The following should work:
let split2 l = (List.map fst l, List.map snd l)
let flatten2' (l1, l2) = (List.flatten l1, List.flatten l2)
let flatten2 l = flatten2' (split2 l)
Here, split2 will turn a ('a list * 'b list) list into a ('a list list * 'b list list) (fst and snd return the first and second component of a pair, respectively) and flatten2' will individually flatten the two components. And flatten2 will finally do what you require. You can also pack this into a single function, but I think this is easier to understand.
Note that neither List.map nor List.flatten is tail-recursive; if you need tail-recursive versions, there are other libraries that have them, or you can build them from the standard library using rev_xxx functions or write them from scratch.
How to create a function to zip and unzip two lists as tupled lists in Standard ML?
Example:
unzip [[1,4],[2,5],[3,6]] -> [1,2,3] [4,5,6]
zip [1,2,3] [0,2,4] -> [[1,0],[2,2],[3,4]]
I figured out what I was doing wrong.
Here's the code:
fun zip nil nil = nil
| zip nil l = l
| zip l nil = l
| zip (h::t) (k::l) = [h,k]::(zip t l)
fun mapcan(f,nil) = nil | mapcan(f,h::t) = (f h)#(mapcan(f,t))
fun unzip (l) = if (l = nil) then nil else [(map head l),(mapcan tail l)]
Unzipping is slightly more difficult. We need map functions that select the first and second elements of a two-element list over the zipped list. Since the problem is somewhat under-specified by the example, we will put the rest of the longer list into the first list. To avoid problems with the empty tails for the shorter list, we use the mapcan function that appends the tail lists.
It is usually not a good idea to use head and tail, but instead to use pattern matching. You can encode unzip a bit more elegantly as follows:
fun unzip l =
case l
of nil => (nil, nil)
| (a,b)::tl =>
let val (l1, l2) = unzip tl
in (a::l1, b::l2) end
Also as one of the commenters above mentioned, zip and unzip typically work on pairs of lists, and lists of pairs respectively.
There is absolutely no need for the lexical scoping introduced by the let statement. By defining the projection functions, one can actually get a far more concise and elegant representation :
fun fst p =
case p of
(x,_) => x
fun snd p =
case p of
(_,y) => y
fun unzip lp =
case lp of
[] => ([], [])
| (x,y) :: lp' => (x :: (fst (unzip lp')), y :: (snd (unzip lp')))
There is good reason why this works, which is that Type-Inference from the SML compiler is strong enough to deduce the types of the terms from the case statements and the cons statements. The projection functions are deduced before, and the CSP for the Type-Constraints is solvable. IMO, this is far more elegant than the solutions presented before with the let statement.
Compiler