I have this function which removes occurrences of a given element within the list of lists.
remove :: Eq a => a -> [[a]] -> [[a]]
remove y [] = error "Can't remove an element from an empty list"
remove y xs = map (filter(/=y)) xs
How would I be able to do the same using List comprehension
Thank you
For each l in xs, add filter (/= xs) l to the resulting list:
remove y xs = [filter (/= y) l | l <- xs]
or, removing filter by nesting comprehensions.
For each xs in xss and for each x in xs, keep x only if it's different from y:
remove y xss = [ [x| x <- xs, x /= y] | xs <- xss]
It's OK if you're just practicing , but your version with map is way better :)
I guess something along the lines of:
remove y ls = [f|l <- ls, let f = filter (/= y) l]
should be fine.
It basicly states that for every binding l you can make in the list ls, add the filtered list f to the resulting list.
Related
A list of integers is given. Determine whether the list contains the same numbers that follow one after another. Return the index of the first repeated number or -1 if there are no repetitions.
The function should output:
duplicateIndex [1,8,3,3,4] -> 2
duplicateIndex [7,7,3,2,5] -> 0
duplicateIndex [1,2] -> -1
I tried to solve as follows, but this solution is not correct!
let duplicateIndex lst = [if x ==y then lst !!x else (-1) | x:ys <- tails lst, y <- ys]
Help me fix the code.
Your list comprehension expression returns a list element rather than a list index (as specified). Furthermore, there is nothing to keep track of the current index value.
If we look for a solution that is easy to visualize, we can try using zip. When it is about comparing 2 adjacent elements, it is common to use zip xs (tail xs) as an auxiliary list.
But that still does not include any information about indexes. For this, we have to add the index sequence as [0..].
As ultimately we aim to return an index, an interesting list comprehension expression would start like:
[ ... | ((x,y), idx) <- zip (zip xs (tail xs)) [0..], ... constraints ... ]
Let's see what our auxiliary list looks like:
λ>
λ> printAsLines ys = mapM_ (putStrLn . show) ys
λ>
λ> xs = [1,8,3,3,4,7,5,5,2]
λ>
λ> printAsLines $ zip (zip xs (tail xs)) [0..]
((1,8),0)
((8,3),1)
((3,3),2)
((3,4),3)
((4,7),4)
((7,5),5)
((5,5),6)
((5,2),7)
λ>
Furthermore, looking for a repeated number we need to have x == y as a constraint; and we want to return an index, so the left side of the list comprehension has to be idx. This gives:
[ idx | ((x,y), idx) <- zip (zip xs (tail xs)) [0..], x == y ]
Let's test it:
λ>
λ> [ idx | ((x,y), idx) <- zip (zip xs (tail xs)) [0..], x == y ]
[2,6]
λ>
So we're almost done: we just need to take the first element of the last list comprehension, assuming of course there is a first element at all. Otherwise, return -1.
This gives the following code:
duplicateIndex :: Eq α => [α] -> Int
duplicateIndex xs =
let indexes = [ idx | ((x,y), idx) <- zip (zip xs (tail xs)) [0..], x == y ]
in
if (null indexes) then (-1)
else head indexes
The language lazyness ensures that the indexes list will not be evaluated beyond finding the first element.
EDIT:
The function can be written in more compact fashion using zip3:
duplicateIndex :: Eq α => [α] -> Int
duplicateIndex xs =
let idxs = [ idx | (x, y, idx) <- zip3 xs (tail xs) [0..], x == y ]
in if (null idxs) then (-1) else (head idxs)
I just started learning Haskell and I started looking into understanding comprehension which allows me to form a subset by giving conditions to a bigger set.
I tried to make a comprehension that takes a nested list (containing other integer lists) and removes all the positive odd numbers from them and empty inner lists.
testList= [-3]:[-5,8]:[[1,3,5,7,9],[],[4,6,8,10],[1,3,6,7,9],[],[1]]
removingOnlyPosOdds xxs = [ [x | x <-xs, not (odd x && x > 0 )] | xs <- xxs, [] /= xs ]
testList before applying the comprehension function on it looked like:
[[-3],[-5,8],[1,3,5,7,9],[],[4,6,8,10],[1,3,6,7,9],[],[1]]
After applying removingOnlyPosOdds testList
The outcome was
[[-3],[-5,8],[],[4,6,8,10],[6],[]]
So what I realised that "[] /= xs" in the function description was removing the already existent
"[]" inner lists in testList only; but not the new ones that were formed caused by me removing positive odd numbers from the inner lists.
What should be my next step in order to remove those as well code wise?
I want it to look like
[[-3],[-5,8],[4,6,8,10],[6]]
Is there a way to generalise the comprehension to do it in one go?
Or is there another approach which would be much better to deal with the removal of things (like the empty inner lists )and to make a more specified set?
You can add some extra filtering, and prevent doing the same list comprehension twice with a let clause, like:
removingOnlyPosOdds xxs = [ ys | xs <- xxs, let ys = [x | x <-xs, not (odd x && x > 0 )], not (null ys) ]
Or we can just add some extra filtering, like:
removingOnlyPosOdds :: Integral i => [[i]] -> [[i]]
removingOnlyPosOdds = filter (not . null) . map (filter (\x -> not (odd x && x > 0)))
or even more pointfree:
import Control.Monad(liftM2)
removingOnlyPosOdds :: Integral i => [[i]] -> [[i]]
removingOnlyPosOdds = filter (not . null) . map (filter (not . liftM2 (&&) odd (>0)))
For example:
Prelude> removingOnlyPosOdds [[-3],[-5,8],[1,3,5,7,9],[],[4,6,8,10],[1,3,6,7,9],[],[1]]
[[-3],[-5,8],[4,6,8,10],[6]]
I want to get all the occurrences of the characters I have in a string.
So for example if I have the string "nunddrdr" I want to get "nnudddrr".
This is how the code looks like which should achieve this:
usort :: String -> String
l :: String
l = ""
usort (x:xs)
| xs == [] = l ++ [x]
| otherwise = l ++ [n | n <- (x:xs), n = x] ++ usort (xs)
It doesn't work correctly because it also proccesses already used characters.
You have correctly observed that your recursive calls to usort are not removing the characters that have already been used, so you will need to modify the function so that it does this. You can use filter to select only the elements of the list that match some criteria, so we can remove the already used characters like so:
filter (\=x) xs
We can select all of the characters that match x in the same manner, by using
filter (==x) xs
You can use these two things to create your usort function:
usort (x:xs) = x : (filter (==x) xs) ++ usort (filter (/=x) xs)
However, you have failed to consider the case when you will be trying to sort an empty list, so you will also need to add:
usort [] = []
Putting this together, you get
usort::(Eq a)=>[a]->[a]
usort [] = []
usort (x:xs) = x : filter (==x) xs ++ usort (filter (/=x) xs)
In order to split an arbitrary set s into two subsets l and r, in which l has a fixed size n, I have written the following code:
parts :: Int -> [a] -> [([a], [a])]
parts n ls = (filter len . f) ls
where len (lhs,rhs) = length lhs==n -- the condition that the left subset is of fixed size n
f [] = [([],[])]
f (x:xs) = [ (x:l,r) | (l,r)<-f xs] ++ [ (l,x:r) | (l,r)<-f xs]
Here is a sample of its effect. Evaluating parts 2 "12345" yields:
[ ("12","345")
, ("13","245")
, ("14","235")
, ("15","234")
, ("23","145")
, ("24","135")
, ("25","134")
, ("34","125")
, ("35","124")
, ("45","123")
]
Please notice that my solution enumerates all subsets and then filters out the desired ones. I suppose the subsets function is familiar to you:
subsets :: [a] -> [[a]]
subsets [] = [[]]
subsets (x:xs) = map (x:) (subsets xs) ++ subsets xs
Personally, I find my solution disappointing. It filters the correct answers from a larger set. My question to the reader is:
Can you come up with a function that is equivalent to parts, but produces the answer directly without this a-posteriory filter?
Inspired by subsets, you might end up with
import Control.Arrow (first, second)
-- first f (x,y) = (f x, y) ; second f (x, y) = (x, f y)
parts n xs = parts' 0 xs where
parts' l (x:xs) | l < n = map (first (x:)) (parts' (l + 1) xs) ++ -- 1a
map (second (x:)) (parts' l xs) -- 1b
parts' l xs | l == n = [([],xs)] -- 2
parts' _ _ = [] -- 3
l contains the length of the first pair so far. As long as the pair isn't yet long enough, we take the first element of the list, and append it to all first elements in our pairs (1a). We're also going to map it onto the second elements (1b). Note that in this case the length of the first pairs didn't increase.
When the first pairs just happen to be long enough (2), we're going to put all other elements into the second half of the pair.
When the requirements for the guards do not hold (list exhausted), we return [] (3). This approach also retains the relative ordering of elements:
> parts 2 "12345"
[
("12","345"),
("13","245"),
("14","235"),
("15","234"),
("23","145"),
("24","135"),
("25","134"),
("34","125"),
("35","124"),
("45","123")
]
This approach will also work on infinite lists:
> map (second (const "...")) $ take 5 $ parts 3 [1..]
[([1,2,3],"..."),([1,2,4],"..."),([1,2,5],"..."),([1,2,6],"..."),([1,2,7],"...")]
(The second elements in the pairs will still be infinite lists)
Ok this is what I came up with:
parts :: Int -> [a] -> [([a],[a])]
parts n list = parts' 0 (length list) [] [] list where
parts' _ _ ls rs [] = [(ls,rs)]
parts' n' l ls rs as#(x:xs) | n' >= n = [(reverse ls, reverse rs ++ as)]
| n' + l <= n = [(reverse ls ++ as, reverse rs)]
| otherwise = parts' (n' + 1) (l - 1) (x : ls) rs xs
++ parts' n' (l - 1) ls (x : rs) xs
If it doesn't matter if the elements of the subsets are in the same order as they were in the original set, then you can remove the four uses of reverse.
Sliding split can be done using zipWith of inits and tails. For each split produce the solution for a smaller sublist, and append the element at the point of split to all such solutions.
parts 0 xs = [([],xs)]
parts n xs = concat $ zipWith f (inits xs) (init $ tails xs) where
f hs (h:ts) = [(h:t', hs++ts') | (t', ts') <- parts (n-1) ts]
-- f hs [] not possible - init $ tails xs does not produce empty lists
i'm trying to create an infinte reverse add then sort list in haskell
r = map head (iterate rlist [2..])
rlist (x:xs) = [x : xs | x <- xs , x quick $ p+x ]
where p = reverse x
quick [] = []
quick (x:xs) = quick [u |u <- xs, u < x] ++ [x] ++ quick [u | u <- xs , u >= x]
but its not working, any suggestions?
thanks.
I'm not sure how you expect your code to work (perhaps there was a problem when you posted the code). Namely, part of your list comprehension ... x quick $ p + x makes no sense to me - x isn't a function and it isn't a list so reverse x also makes no sense. For that matter you have shadowed x - notice the x in your list comprehension isn't the same as the x in ratslist (x:xs).
A simple solution does exist using read and show to convert the numbers to lists of digits (well, characters, but it works) and back:
import Data.List
myRats = 1 : map ratify myRats
-- Alternatively: myRats = iterate ratify 1
ratify :: Integer -> Integer
ratify n = sortRat (n + rev n)
where
rev = read . reverse . show
sortRat = read . sort . show
And in GHCi:
*Main Data.List> take 10 myRats
[1,2,4,8,16,77,145,668,1345,6677]
I don't quite get your problem, but according to your example, I'd try
rats x = sort (zipWith (+) x (reverse x))
like in rats [1,4,5] which equals [6,6,8].