Your code (the one in your answer) is essentially fine. Just replace isEmpty
by library function null
.
Just a thing about optimization: function encode2
scans all elements twice. This is because the information about the location in the list of the first differing element is not preserved by conta
, which returns just a count.
When people program this problem in their favorite imperative language, they certainly think of preserving a pointer to the rest of the list. It is just a little bit subtler in Haskell, but it can be done too.
The situation can be improved by having a version of counta
that returns both the count and (a pointer to) the rest of the list. Like this:
-- Must return also a pointer to the rest of the input list:
extract :: Eq a => a -> Int -> [a] -> (Int, [a])
extract x0 n [] = (n,[])
extract x0 n (x:xs) = if (x==x0) then extract x0 (n+1) xs
else (n, x:xs)
Testing under ghci
:
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
λ>
λ> :load q68434019.hs
Ok, one module loaded.
λ>
λ> extract 'a' 0 "aaaabccaadeeee"
(4,"bccaadeeee")
λ>
λ> extract 'a' 0 ""
(0,"")
λ>
λ> extract 'z' 0 "aaaabccaadeeee"
(0,"aaaabccaadeeee")
λ>
λ> extract 'z' 42 "aaaabccaadeeee"
(42,"aaaabccaadeeee")
λ>
With this tool in place, it is then easy to solve the problem using a single scan of the input list:
encode3 :: Eq a => [a] -> [(Int,a)]
encode3 [] = []
encode3 (x:xs) = let (count, rest) = extract x 1 xs
in (count, x) : (encode3 rest)