I have the following problem, I want to replicate numbers according to their value in a list, but if it's lower than 0, they do not appear. For example:
myList [1, 4, 3] = [1, 4, 4, 4, 4, 3, 3, 3]
myList [1, 0, 2] = [1, 2, 2]
I was thinking of using my version of replicate (which I'm also using for something else so I can't change the Int -> a -> [a]) but I don't know why there is a complication error, please help me fix, but without the use of map.
myList:: [Int] -> [Int]
myList [] = []
myList (x:xs) = (myReplicate (if x > 0 then x else 0) x) ++ myReplicate xs
myReplicate :: Int -> a -> [a]
myReplicate 0 x = [ ]
myReplicate count x = x : myReplicate (count-1) x
You append with myReplicate xs, but xs is a list of Ints. You should recurse on the tail of the list, so:
myList:: [Int] -> [Int]
myList [] = []
myList (x:xs) = (myReplicate (if x > 0 then x else 0) x) ++ myList xs
This then produces:
Prelude> myList [1,4,3]
[1,4,4,4,4,3,3,3]
It might be better however to make myReplicate work with any Int, so:
myReplicate :: Int -> a -> [a]
myReplicate n _ | n <= 0 = []
myReplicate count x = x : myReplicate (count-1) x
then your myList can be simplified to:
myList:: [Int] -> [Int]
myList [] = []
myList (x:xs) = myReplicate x x ++ myList xs
We can also make use of concatMap :: (a -> [b]) -> [a] -> [b]:
myList:: [Int] -> [Int]
myList = concatMap (\x -> myReplicate x x)
we can generalize this further to let this work with any Foldable:
myList:: Foldable f => f Int -> [Int]
myList = concatMap (\x -> myReplicate x x)
Related
I have to define a function according to this signature:
indexList :: [a] -> [(Int, a)]
The function is supposed to unzip the list elements into a tuple - the first part of the tuple being how far is the tuple from the end of the list - and the second part being the original element itself. (Must be recursive, and I can't use the length function).
expecting this test to be true:
indexList [True, False, True] == [(2, True), (1, False), (0, True)]
I have gotten here so far:
indexList [] = []
indexList (x : xs) = ({-HowFarIsIt-}, x) : indexList xs
You can look at the result of the next tuple of the result, so:
indexList :: [a] -> [(Int, a)]
indexList [] = []
indexList [x] = [(0, x)]
indexList (x : xs) = … : ys
where ys#((i,_):_) = indexList xs
where I leave filling in … as an exercise.
You can also work with a helper function to enable total pattern matching:
import Data.List.NonEmpty(NonEmpty((:|)), (<|))
indexList :: [a] -> [(Int, a)]
indexList [] = []
indexList (x : xs) = let (x :| xs) = indexList' x xs in x : xs
indexList' :: a -> [a] -> NonEmpty [(a, Int)]
indexList' x [] = (0, x) :| []
indexList' x xs = … <| ys
where ys#((i,_) :| _) = indexList' x xs
I want to write a function that takes two lists as arguments and creates a list with a pair from each list consecutively, but in reverse.
for example:
reversezipLists [1, 2, 3] ['a', 'b', 'c']
would produce [('c', 3), ('b', 2), ('a', 1)].
Here is my attempt:
reversezipLists :: [a] -> [b] -> [(b,a)]
reversezipLists [] [] = []
reversezipLists [] ys = []
reversezipLists xs [] = []
reversezipLists (x:xs) (y:ys) = (y,x) : reversezipLists xs ys
the problem is the output of my code is: [('a',1),('b',2),('c',3)]. How can I reverse it?
Use an accumulator:
reversezipLists :: [a] -> [b] -> [(b, a)]
reversezipLists = go [] where
go acc [] _ = acc
go acc _ [] = acc
go acc (h1:t1) (h2:t2) = go ((h2, h1) : acc) t1 t2
Bonus points: the function is tail recursive. The basic idea is that we append new pairs to the acc during the left-to-right traverse through the lists. The stackish nature of Haskell lists makes the result reversed. Note that it will truncate longer list.
If you want to throw an error when the lists' lengths don't match, you can play a bit with patterns:
reversezipLists :: [a] -> [b] -> [(b, a)]
reversezipLists = go [] where
go acc [] [] = acc
go acc (h1:t1) (h2:t2) = go ((h2, h1) : acc) t1 t2
go _ _ _ = error "lists' sizes don't match"
r (x:xs) (y:ys) = (r xs ys) ++ [(y,x)]
r [] [] = []
r [1, 2, 3] ['a', 'b', 'c'] = [('c',3),('b',2),('a',1)]
it works only on lists of the same length
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]
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
How to implement insert using foldr in haskell.
I tried:
insert'' :: Ord a => a -> [a] -> [a]
insert'' e xs = foldr (\x -> \y -> if x<y then x:y else y:x) [e] xs
No dice.
I have to insert element e in list so that it goes before first element that is larger or equal to it.
Example:
insert'' 2.5 [1,2,3] => [1.0,2.0,2.5,3.0]
insert'' 2.5 [3,2,1] => [2.5,3.0,2.0,1.0]
insert'' 2 [1,2,1] => [1,2,2,1]
In last example first 2 is inserted one.
EDIT:
Thanks #Lee.
I have this now:
insert'' :: Ord a => a -> [a] -> [a]
insert'' e xs = insert2 e (reverse xs)
insert2 e = reverse . snd . foldr (\i (done, l) -> if (done == False) && (vj e i) then (True, e:i:l) else (done, i:l)) (False, [])
where vj e i = e<=i
But for this is not working:
insert'' 2 [1,3,2,3,3] => [1,3,2,2,3,3]
insert'' 2 [1,3,3,4] => [1,3,2,3,4]
insert'' 2 [4,3,2,1] => [4,2,3,2,1]
SOLUTION:
insert'' :: Ord a => a -> [a] -> [a]
insert'' x xs = foldr pom poc xs False
where
pom y f je
| je || x > y = y : f je
| otherwise = x : y : f True
poc True = []
poc _ = [x]
Thanks #Pedro Rodrigues (It just nedded to change x>=y to x>y.)
(How to mark this as answered?)
You need paramorphism for that:
para :: (a -> [a] -> r -> r) -> r -> [a] -> r
foldr :: (a -> r -> r) -> r -> [a] -> r
para c n (x : xs) = c x xs (para c n xs)
foldr c n (x : xs) = c x (foldr c n xs)
para _ n [] = n
foldr _ n [] = n
with it,
insert v xs = para (\x xs r -> if v <= x then (v:x:xs) else (x:r)) [v] xs
We can imitate paramorphisms with foldr over init . tails, as can be seen here: Need to partition a list into lists based on breaks in ascending order of elements (Haskell).
Thus the solution is
import Data.List (tails)
insert v xs = foldr g [v] (init $ tails xs)
where
g xs#(x:_) r | v <= x = v : xs
| otherwise = x : r
Another way to encode paramorphisms is by a chain of functions, as seen in the answer by Pedro Rodrigues, to arrange for the left-to-right information flow while passing a second copy of the input list itself as an argument (replicating the effect of tails):
insert v xs = foldr g (\ _ -> [v]) xs xs
where
g x r xs | v > x = x : r (tail xs) -- xs =#= (x:_)
| otherwise = v : xs
-- visual aid to how this works, for a list [a,b,c,d]:
-- g a (g b (g c (g d (\ _ -> [v])))) [a,b,c,d]
Unlike the version in his answer, this does not copy the rest of the list structure after the insertion point (which is possible because of paramorphism's "eating the cake and having it too").
Here's my take at it:
insert :: Ord a => a -> [a] -> [a]
insert x xs = foldr aux initial xs False
where
aux y f done
| done || x > y = y : f done
| otherwise = x : y : f True
initial True = []
initial _ = [x]
However IMHO using foldr is not the best fit for this problem, and for me the following solution is easier to understand:
insert :: Int -> [Int] -> [Int]
insert x [] = [x]
insert x z#(y : ys)
| x <= y = x : z
| otherwise = y : insert x ys
I suppose fold isn't handy here. It always processes all elements of list, but you need to stop then first occurence was found.
Of course it is possible, but you probable don't want to use this:
insert' l a = snd $ foldl (\(done, l') b -> if done then (True, l'++[b]) else if a<b then (False, l'++[b]) else (True, l'++[a,b])) (False, []) l