Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell run-length encoding function

This encoding function expects the following output, code "aaccbbaa" = [('a',2),('c',2),('b',2),('a',2)

However, this is my output. code "aaccbbaa" = [('a',4),('c',2),('b',2)]

Here is my function,

code :: Eq a => [a] -> [(a,Int)]
code [] = []
code (x:xs) = [(x, length(filter(==x)(x:xs)))] ++ code(filter (/=x)(xs))

How do I make it recount that when the next alpha letter appears?

like image 606
BCKN Avatar asked May 22 '26 18:05

BCKN


2 Answers

There is a group function in Data.List

code :: Eq a => [a] -> [(a,Int)]
code = map (\x -> (head x, length x)) . group

λ> code "aaccbbaa"
[('a',2),('c',2),('b',2),('a',2)]
like image 82
Kamel Avatar answered May 24 '26 21:05

Kamel


A foldr with a helper function should be sufficient to handle this job as follows;

code :: Char -> [(Char,Int)] -> [(Char,Int)]
code c [(_,0)]    = [(c,1)]
code c ((x,n):ts) | c == x    = (x,n+1):ts
                  | otherwise = (c,1):(x,n):ts

rle :: String -> [(Char,Int)]
rle = foldr code [(' ',0)]

Well as per your comment to accept any type with instances of Eq Class we may simplify the rle function. On the other hand the accepted answer involves 3 time taking operations like group, map and length. For a single use it won't matter, however if you will be using this function millions of times on some words or sentences then i would advise the following which only runs once through the list.

rle :: Eq a => [a] -> [(a,Int)]
rle = foldr code []
      where code c []         = [(c,1)]
            code c ((x,n):ts) | c == x    = (x,n+1):ts
                              | otherwise = (c,1):(x,n):ts
like image 43
Redu Avatar answered May 24 '26 22:05

Redu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!