removing direct duplicates on a list - haskell

So i am supposed to remove direct duplicates that are next to each other from a list. For example 1,3,3,3,2,4,4,2,4] = [1,3,2,4,2,4] or [63,65,65,64,65,63,65,65,64,64,65] = [63,65,64,65,63,65,64,65]. My code just removes all duplicates. I think my problem is that i compare with elem and i need a function that only compares with the next element.
module Blueprint where
import Prelude
compress :: [Int] -> [Int]
compress [] = []
compress (x:xs) | x `elem` xs = compress xs
| otherwise = x : compress xs

Right now you are checking if x has a duplicate in the rest of the function. You actually want to check if the next element is a duplicate. You can do this by looking at the first two elements of a list not just the first one.
compress :: [Int] -> [Int]
compress [] = []
compress [x] = [x]
compress (x:x2:xs) | x == x2 = compress (x2:xs)
| otherwise = x : compress (x2:xs)

The group function finds adjacent equal values and groups them together. So your function may be implemented as
compress = map head . group
At first, it may look dangerous to use head; however, a promise of group is that each element it returns is a non-empty list.

I've been getting a lot of bang from this little fold technique lately:
smash :: Eq a => [a] -> [a]
smash xs = foldr go (`seq` []) xs Nothing
where
go x r (Just prev)
| x == prev = r (Just x)
go x r _ = x : r (Just x)

Related

Haskell: merging list of lists

given a list of list pairs ::[a,a], I would like to return the possible combinations of lists, where the sublists have been merged on the last of one sublit matching head of the next.
for example
-- combine two lists if they front and back match
merge :: Eq a => [[a]] -> [[a]]
merge (x:y:ys) | last x == head y = merge $ (x ++ (drop 1 y)) : ys
| otherwise = []
merge xs = xs
combinations :: Eq a => [[a]] -> [[a]]
combinations = nub . concatMap merge . permutations
λ= merge [1,2] [2,3]
[1,2,3]
-- there should be no duplicate results
λ= combinations [[1,3],[1,3],[1,3],[1,3],[2,1],[2,1],[2,1],[2,2],[3,2],[3,2],[3,2]]
[[1,3,2,2,1,3,2,1,3,2,1,3],[1,3,2,1,3,2,2,1,3,2,1,3],1,3,2,1,3,2,1,3,2,2,1,3]]
-- the result must be a completely merged list or an empty list
λ= combinations [[1,3], [3,1], [2,2]]
[]
λ= combinations [[1,3], [3, 1]]
[[1,3,1],[3,1,3]]
λ= combinations [[1,3],[3,1],[3,1]]
[[3,1,3,1]]
I can't quite wrap my head around the recursion needed to do this efficiently.
I ended with this solution, but it contains duplicates (you can use Data.List(nub) to get rid of them).
import Data.List(partition)
main :: IO ()
main = do
print $ show tmp
input = [[1,3],[1,3],[1,3],[1,3],[2,1],[2,1],[2,1],[2,2],[3,2],[3,2],[3,2]]
tmp = combinations input
-- this function turns list into list of pair, first element is element of the
-- input list, second element is rest of the list
each :: [a] -> [a] -> [(a, [a])]
each h [] = []
each h (x:xs) = (x, h++xs) : each (x:h) xs
combinations :: (Eq a) => [[a]] -> [[a]]
combinations l = concat $ map combine $ each [] l
where
-- take pair ("prefix list", "unused lists")
combine :: (Eq a) => ([a], [[a]]) -> [[a]]
combine (x, []) = [x]
combine (x, xs) = let
l = last x
-- split unused element to good and bad
(g, b) = partition (\e -> l == head e) xs
s = each [] g
-- add on element to prefix and pass rest (bad + good except used element) to recursion. so it eat one element in each recursive call.
combine' (y, ys) = combine (x ++ tail y, ys ++ b)
-- try to append each good element, concat result
in concat $ map combine' s
I'm not sure if I fully understand what you want to do, so here are just a few notes and hints.
given a list of list pairs ::[a,a]
(...) for example
λ= merge [1,2] [2,3]
Firstly those are not lists of pairs, each element of the list is an integer not a pair. They just happen to be lists with two elements. So you can say they are of type [Int] or an instance of type [a].
the sublists have been merged on the last of one sublit matching head of the next.
This suggests that the size of the lists will grow, and that you will constantly need to inspect their first and last elements. Inspecting the last element of a list implies traversing it each time. You want to avoid that.
This suggests a representation of lists with extra information for easy access. You only need the last element, but I'll put first and last for symmetry.
-- lists together with their last element
data CL a = CL [a] a a
cl :: [a] -> CL a
cl [] = error "CL from empty list"
cl xs = CL xs (head xs) (last xs)
clSafe :: [a] -> Maybe (CL a)
clSafe [] = Nothing
clSafe xs = Just (cl xs)
clFirst (CL _ x _) = x
clLast (CL _ _ x) = x
compatible cs ds = clLast cs == clFirst ds
Perhaps better, maybe you should have
data CL a = CL [a] a a | Nil
And to include an empty list that is compatible with all others.
Another point to take into account is that if e.g., you have a list xs and want to find lists ys to combine as ys++xs, then you want it to be very easy to access all ys with a given last element. That suggests you should store them in a suitable structure. Maybe a hash table.

How to compare multiple strings within in the same list in Haskell

I am trying to write a Haskell function that takes in a list of strings, compares all the strings in the list, and outputs a list of strings that are of the longest length. I want to do this without any predefined functions or imports, I want to try and figure it out all recursively. For example:
longeststrings["meow","cats","dog","woof"] -> ["meow","cats","woof"]
I know it is a silly example, but I think it proves the point.
I want to do something like
longeststrings:: [string] -> [string]
longeststrings [] = []
longeststrings [x:xs] = if (x > xs) x:longeststrings[xs]
But I don't know how to only take the largest size strings out of the list, or remove the smallest ones. I would appreciate any help.
you could trivially keep track of the longest length string and an accumulator of values of that length.
longestStrings :: [String] -> [String]
longestStrings = go [] 0
where
go acc _ [] = acc -- base case
go acc n (x:xs)
| length x > n = go [x] (length x) xs
-- if x is longer than the previously-seen longest string, then set
-- accumulator to the list containing only x, set the longest length
-- to length x, and keep looking
| length x == n = go (x:acc) n xs
-- if x is the same length as the previously-seen longest string, then
-- add it to the accumulator and keep looking
| otherwise = go acc n xs
-- otherwise, ignore it
or, as Davislor rightly mentions in the comments, this can be implemented as a fold by teaching the helper function to determine its own longest length
longestStrings :: [String] -> [String]
longestStrings = foldr f []
where
f x [] = [x]
f x yss#(y:_) =
case compare (length x) (length y) of
GT -> [x]
EQ -> x : yss
LT -> yss
As requested, here’s a version with and without the use of where. I think this is a good demonstration of why the advice not to use where is bad advice. I think the first version is a lot easier to understand.
Keep in mind, functional programming isn’t a monastic vow to forswear certain keywords out of masochism. Nor is it a checklist of fashion tips (where is so last season!). “You should avoid that construct arbitrarily because it’s not the ‘functional’ thing to do” really is not how it works. So you shouldn’t uglify your code for the sake of a tip like that.
It is often a good idea to follow the same coding style as other programmers so they will find it easier to understand you. (For example, Adam Smith was subtly trying to train you that acc is a common name for an accumulator and go a common name for a recursive helper function, and they help other programmers figure out the pattern he’s using.) But in fact Haskell programmers do use where, a lot.
Anyway, the code:
longeststrings :: [String] -> [String]
{- Filters all strings as long as any other in the list. -}
longeststrings = foldr go []
where
go x [] = [x]
go x leaders | newlength > record = [x]
| newlength == record = x:leaders
| otherwise = leaders
where
record = (length . head) leaders
newlength = length x
longestStringsUsingLambda :: [String] -> [String]
longestStringsUsingLambda = foldr
(\x leaders ->
if leaders == [] then [x]
else case compare (length x) (length $ head leaders) of
GT -> [x]
EQ -> x:leaders
LT -> leaders )
[]
main :: IO ()
main = let testcases = [ ["meow","cats","dog","woof"],
["foo","bar","baz"],
["meep","foo","bar","baz","fritz","frotz"]
]
in foldMap print $
map longestStringsUsingLambda testcases
You can try eliminating the let testcases = ... and see if you consider that an improvement.

Remove a Character Sequence From a String

Consider a function, which takes a string and returns a list of all possible cases in which three subsequent 'X's can be removed from the list.
Example:
"ABXXXDGTJXXXDGXF" should become
["ABDGTJXXXDGXF", "ABXXXDGTJDGXF"]
(The order does not matter)
here is a naive implementation:
f :: String -> [String]
f xs = go [] xs [] where
go left (a:b:c:right) acc =
go (left ++ [a]) (b:c:right) y where -- (1)
y = if a == 'X' && b == 'X' && c == 'X'
then (left ++ right) : acc
else acc
go _ _ acc = acc
I think the main problem here is the line marked with (1). I'm constructing the left side of the list by appending to it, which is generally expensive.
Usually something like this can be solved by this pattern:
f [] = []
f (x:xs) = x : f xs
Or more explicitly:
f [] = []
f (x:right) = x : left where
left = f right
Now I'd have the lists right and left in each recursion. However, I need to accumulate them and I could not figure out how to do so here. Or am I on the wrong path?
A solution
Inspired by Gurkenglas' propose, here is a bit more generalized version of it:
import Data.Bool
removeOn :: (String -> Bool) -> Int -> String -> [String]
removeOn onF n xs = go xs where
go xs | length xs >= n =
bool id (right:) (onF mid) $
map (head mid:) $
go (tail xs)
where
(mid, right) = splitAt n xs
go _ = []
removeOn (and . map (=='X')) 3 "ABXXXDGTJXXXDGXF"
--> ["ABDGTJXXXDGXF","ABXXXDGTJDGXF"]
The main idea seems to be the following:
Traverse the list starting from its end. Make use of a 'look-ahead' mechanism which can examine the next n elements of the list (thus it must be checked, if the current list contains that many elements). By this recursive traversal an accumulating list of results is being enhanced in the cases the following elements pass a truth test. In any way those results must be added the current first element of the list because they stem from shorter lists. This can be done blindly, since adding characters to a result string won't change their property of being a match.
f :: String -> [String]
f (a:b:c:right)
= (if a == 'X' && b == 'X' && c == 'X' then (right:) else id)
$ map (a:) $ f (b:c:right)
f _ = []

How can this function be written using foldr?

I have this simple function which returns a list of pairs with the adjacents elements of a list.
adjacents :: [a] -> [(a,a)]
adjacents (x:y:xs) = [(x,y)] ++ adjacents (y:xs)
adjacents (x:xs) = []
I'm having problems trying to write adjacents using foldr. I've done some research but nothing seems to give me a hint. How can it be done?
Tricky folds like this one can often be solved by having the fold build up a function rather than try to build the result directly.
adjacents :: [a] -> [(a, a)]
adjacents xs = foldr f (const []) xs Nothing
where f curr g (Just prev) = (prev, curr) : g (Just curr)
f curr g Nothing = g (Just curr)
Here, the idea is to let the result be a function of type Maybe a -> [(a, a)] where the Maybe contains the previous element, or Nothing if we're at the beginning of the list.
Let's take a closer look at what's going on here:
If we have both a previous and a current element, we make a pair and pass the current element to the result of the recursion, which is the function which will generate the tail of the list.
f curr g (Just prev) = (prev, curr) : g (Just curr)
If there is no previous element, we just pass the current one to the next step.
f curr g Nothing = g (Just curr)
The base case const [] at the end of the list just ignores the previous element.
By doing it this way, the result is as lazy as your original definition:
> adjacents (1 : 2 : 3 : 4 : undefined)
[(1,2),(2,3),(3,4)*** Exception: Prelude.undefined
I don't think your function is a good fit for a fold, because it looks at two elements rather than one.
I think the best solution to the problem is
adjacents [] = []
adjacents xs = zip xs (tail xs)
But we can shoehorn it into a travesty of a fold if you like. First an auxilliary function.
prependPair :: a -> [(a,a)] -> [(a,a)]
prependPair x [] = [(x,b)] where b = error "I don't need this value."
prependPair x ((y,z):ys) = ((x,y):(y,z):ys)
adjacents' xs = init $ foldr prependPair [] xs
I feel like I've cheated slightly by making and throwing
away the last element with the error value, but hey ho, I already said I don't think
foldr is a good way of doing this, so I guess this hack is an example of it not being a fold.
You can also try unfoldr instead of foldr.
import Data.List
adjacents xs = unfoldr f xs where
f (x:rest#(y:_)) = Just ((x,y), rest)
f _ = Nothing

Haskell: String splitting. Learning algo

I've seen the other threads about missing split function but I didn't want to peek as I do this for learning purposes and want to figure out myself. So here it is:
split :: Char -> String -> [String]
split c xs | null f = []
| otherwise = f : split c s'
where (f,s) = break (== c) xs
s' | null s = s
| otherwise = tail s
It seems to work fine (please tell me if anything is wrong with it) but when I use a splitting character that is not in the string then the function returns a list with a single element of the original string whereas I want it to return an empty list. I can't figure out how to do it.
Any ideas?.
You can simply write a wrapper function, changing the result of your original one:
split' x xs = go (split x xs) where
go [_] = []
go ys = ys
There are many ways to write a split function, e.g.
split x xs = foldl' go [[]] xs where
go (ys:yss) y | y == x = []:ys:yss
| otherwise = (y:ys):yss
or
import Data.List
split x xs = map tail $ groupBy (const (/=x)) (x:xs)

Resources