I am trying to make a list of pairs in ocaml, but the problem is when the lists' length are different i don't hot to make pairs (a,b) when one of the elements doesn't exist.
Most likely you'll have to create a type to encapsulate the situations of the differing length,
type ('a,'b) combined = Both of 'a * 'b | Left of 'a | Right of 'b
let rec zipwith xs ys = match xs,ys with
| x::xs,y::ys -> Both (x,y) :: (zipwith xs ys)
| x::xs, [] -> Left x :: (zipwith xs ys)
| [], y::ys -> Right y :: (zipwith xs ys)
| [], [] -> []
# zipwith [1;2;3] [1;2];;
- : (int, int) combined list = [Both (1, 1); Both (2, 2); Left 3]
You'll have to make optimizations regarding tail-calls for this to work on long lists, but this is a start of how to approach the problem.
Related
I am learning Haskell at the moment and have come to a bit of a standstill. I'm trying to write a function that takes a predicate p and a list xs and returns the list of those elements of xs which immediately follow an element which passes the predicate p. Here is what I have :
afterFilter :: (a -> Bool) -> [a] -> [a]
afterFilter x (y:ys) =
if x y
then (map head [ys])
else
afterFilter x (tail ys)
test input : afterFilter (<0) [-4,7,-4,-8,3,-3,-6,0,-9,-1]
output : [7]
The trick is to pull two elements out of the input list by pattern-matching two cons cells. If the first element passes the predicate, we stick the second on the output. But don't forget to stick the second element back on the input list when you make the recursive call.
afterFilter :: (a -> Bool) -> [a] -> [a]
afterFilter f [] = [] -- input list is empty
afterFilter f [x] = [] -- input list has only one element - no "next element" to return
afterFilter f (x:y:xs) =
let ys = afterFilter f (y:xs)
in (if f x then y:ys else rest)
However, a higher-level - and much more Haskellish - way to approach the problem would be to break it down into a pipeline of operations.
Pair up each item in the list with the element that follows it using zip, so we have a list of (element, next) pairs.
Use filter to drop the pairs for which element does not pass the predicate.
Use map to extract the next part of each surviving pair.
So the code looks like this:
pairWithSuccessors :: [a] -> [(a, a)]
pairWithSuccessors xs = zip xs (tail xs)
afterFilter :: (a -> Bool) -> [a] -> [a]
afterFilter p xs =
let withSuccessors = pairWithSuccessors xs (tail xs)
filtered = filter (\(element, next) -> p element) withSuccessors
filteredSuccessors = map (\(element, next) -> next) filtered
in filteredSuccessors
Or, written in point-free style:
afterFilter p = map snd . filter (p . fst) . pairWithSuccessors
Functions built with the composition operator . are read right-to-left: first pairWithSuccessors, then filter (p . fst), then map snd over the result.
GHC is good at working with lists: when compiled with optimisations, both approaches should produce roughly the same machine code - that is, there's no performance cost to the high-level solution
Following what you did, there are some strange things with your code :
The map head [ys] is very odd, and causes your function to stop : At the first element matching the predicate, your function returns a list containing its immediate successor and stops there. You still need to process the rest of the list.
Also, following your definition of the problem, each item which is a successor of an item passing the predicate should be on the resulting array. I may be wrong, but what I understood is that afterFilter (<0) [-1, -1, 1] should return [-1, 1].
However, you're discarding one element you didn't check for by calling tail ys : You checked for y, but not for head ys.
Finally, by adding the edge cases, here is what you get :
afterFilter :: (a -> Bool) -> [a] -> [a]
afterFilter _ [] = []
afterFilter _ [_] = []
afterFilter x (y:ys#(z:zs)) =
if x y
then z : afterFilter x ys
else
afterFilter x ys
Try:
afterFilter :: (a -> Bool) -> [a] -> [a]
afterFilter p [] = []
afterFilter p [_] = []
afterFilter p (x1:x2:xs)
| p x1 = x2:rest
| otherwise = rest
where rest = afterFilter p (x2:xs)
Or
afterFilter' :: (a -> Bool) -> [a] -> [a]
afterFilter' p xs = map snd $ filter (\(x, _) -> p x) $ zip xs (tail xs)
Or
afterFilter'' :: (a -> Bool) -> [a] -> [a]
afterFilter'' p xs = [y | (x, y) <- zip xs (tail xs), p x]
What is the best way to find out if a number in a list is within the range of a second list, using a Maybe data type?
What I have so far:
getElems :: [Int] -> [a] -> [Maybe a]
getElems [xs] ys
| head(tail[(xs)]) > head(tail[(ys)]) = [Nothing]
| otherwise = [Just xs]
It needs to return those elements that correspond to the positions specified. Depending on if a position is greater than the list size it returns Nothing, else Just value.
For example:
getElems [2,4] [1..10] ) [Just 3,Just 5]
getElems [2,4] [1..4] ) [Just 3,Nothing]
You can write an getElementByIndex which does that for a single list:
getElementByIndex :: Int -> [a] -> Maybe a
getElementByIndex n [] = Nothing
getElementByIndex n (x:xs) = if (n == 0)
then Just x
else getElementByIndex (n - 1) xs
And then just map it to get an answer:
getElems :: [Int] -> [a] -> [Maybe a]
getElems xs ys = map (\x -> getElementByIndex x ys) xs
Demo in ghci:
λ> getElems [2,4] [1..10]
[Just 3,Just 5]
λ> getElems [2,4] [1..4]
[Just 3,Nothing]
rmdup :: [Int] -> [Int]
rmdup [] = []
rmdup (x:xs) | x `elem` xs = rmdup xs
| otherwise = x: rmdup xs
The code above removes duplicate from a list of Integer but it removes the first occurrence and keeps the second one. For instance:
rmdup [1,2,3,1,4]
will result:
[2,3,1,4]
How can I change it to keep the order and yield this: [1,2,3,4]? Note, I don't want to use built-in functions.
How about the following? This avoids the crazily inefficient acc ++ [x] and also to reverse the given list twice:
rmdup :: Eq a => [a] => [a]
rmdup xs = rmdup' [] xs
where
rmdup' acc [] = []
rmdup' acc (x:xs)
| x `elem` acc = rmdup' acc xs
| otherwise = x : rmdup' (x:acc) xs
One way to achieve what you want is to pass the input list in the reverse order and once when the computation is finished then reverse the result again. Although, this solution is not efficient.
rmdup :: [Int] -> [Int]
rmdup xs = reverse $ rmdup' (reverse xs)
where
rmdup' [] = []
rmdup' (x:xs) | x `elem` xs = rmdup' xs
| otherwise = x: rmdup' xs
Demo:
ghci> rmdup [1,2,3,1,4]
[1,2,3,4]
You want to ignore those later occurrences of an element if you saw it before, then you need to record what you have seen, looks like foldl or foldl' is what you are looking for.
Here is a possible implementation:
import Data.List (foldl')
rmdup :: (Eq a) => [a] -> [a]
rmdup = foldl' step []
where step acc x
| x `elem` acc = acc
| otherwise = acc++[x]
Since elem is O(n), the solutions based on using it to check each element are O(n^2).
The "standard" efficient solution to the duplicates problem is to sort the list before checking for duplicates. Here, since we need to preserve elements, we have to be a bit more careful.
import Data.List
import Data.Ord
rmdupSorted :: Eq b => [(a,b)] -> [(a,b)]
rmdupSorted (x#(_,xb):xs#((_,yb):_)) | xb == yb = rmdupSorted xs
| otherwise = x : rmdupSorted xs
rmdupSorted xs = xs -- 0 or 1 elements
rmdup :: Ord a => [a] -> [a]
rmdup = map snd . sort . rmdupSorted . sortBy (comparing snd) . zip [0..]
main = print $ rmdup [1,2,3,4,5,4,6,1,7]
Assuming that the sortBy function is a stable sort, the rmdup function will remove all the duplicate occurrences of any element but for the one occurring last. If sortBy is not stable, then rmdup will remove all the occurrences but for an unspecified one (i.e., rmdup [1,2,1] could return [1,2] instead of [2,1].).
Complexity is now O(n log n).
We now need to rewrite the above without library functions, as the OP requested. I will leave this as an exercise to the reader. :-P
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
I'm trying to make a recursive function to get the transpose of a list of lists, n x p to p x n. But i'm unable to do so. I've been able to make a function to transpose a 3 x n list of lists to an n x 3 one:
let rec drop1 list=
[(match (List.nth list 0) with [] -> [] | a::b -> b);
(match (List.nth list 1) with [] -> [] | a::b -> b);
(match (List.nth list 2) with [] -> [] | a::b -> b);]
let rec transpose list=
if List.length (List.nth list 0) == 0 then []
else [(match (List.nth list 0) with [] -> 0 | a::b -> a);
(match (List.nth list 1) with [] -> 0 | a::b -> a);
(match (List.nth list 2) with [] -> 0 | a::b -> a)]
:: transpose (drop1 list)
But I'm not able to generalize it. I'm surely thinking in the wrong direction. Is this generalizable? Is there a better solution? Please help.
let rec transpose list = match list with
| [] -> []
| [] :: xss -> transpose xss
| (x::xs) :: xss ->
(x :: List.map List.hd xss) :: transpose (xs :: List.map List.tl xss)
Taking advantage of syntax changes since answer first posted:
let rec transpose list = match list with
| [] -> []
| [] :: xss -> transpose xss
| (x::xs) :: xss ->
List.(
(x :: map hd xss) :: transpose (xs :: map tl xss)
)
I know this is an old question, but I recently had to solve this as part of an exercise I was doing, and I came across #sepp2k's solution, but I couldn't understand how it worked, so I tried to arrive at it by myself.
This is essentially the same algorithm, but a little bit more terse, as it does not destructure the list of lists. I thought I would post it here in case anyone else is searching, and might find this way of expressing it useful:
let rec transpose = function
| []
| [] :: _ -> []
| rows ->
List.map List.hd rows :: transpose (List.map List.tl rows)
Assuming the matrix is rectangular (otherwise Invalid_argument "map2" will be raised):
let transpose m =
if m = [] then [] else
List.(fold_right (map2 cons) m ## map (fun _ -> []) (hd m))
Note that map (fun _ -> []) (hd m) just creates a list of empty lists, of length equal to the number of columns in m.
So a clearer representation of this code would be:
let transpose m =
if m = [] then [] else
let open List in
let empty_rows = map (fun _ -> []) (hd m) in
fold_right (map2 cons) m empty_rows