I need to write a function that takes a string of gggggggeeeeetttttt and can count how many times the letter repeats and output as g7e5t6.
I've only just started Haskell so not really sure at all where to start.
I need to write a function that takes a string of gggggggeeeeetttttt and can count how many times the letter repeats and output as g7e5t6.
I've only just started Haskell so not really sure at all where to start.
The function group will group together identical elements in a list. Since a string is a list of characters, we have:
group "ggggeeetttt" = ["gggg","eee","tttt"]
To get the letter, we can use map head, since head takes the first element of a string (or any list):
map head ["gggg","eee","tttt"] = ['g','e','t']
Now, we want to know how many elements there are in each substring. This can be done using map length:
map length ["gggg","eee","tttt"] = [4,3,4]
Let's turn these numbers back into strings:
map show [4,3,4] = ["4","3","4"]
Now we need to combine the original list and length list somehow. We can do this as follows:
zipWith (:) ['g','e','t'] ["4","3","4"]
zipWith will apply the specified function to paired elements in the two lists. Here I've used (:), which adds an element to the start of the list.
This gives you all the building blocks you need to do what you want. For example, this should work, although I haven't tested it:
f s = concat $ zipWith (:) letters lengths
where
groups = group s
letters = map head groups
lengths = map (show . length) groups
Variant with comprehensions, imo a bit prettier (considering previous explanations just code):
ghci> let s = "gggggggeeeeetttttt"
ghci> putStrLn $ concat [head g: show (length g) | g <- group s]
g7e5t6
The best way to start, is to figure out your problem. I would suggest the following method:
String and returns, a list of strings ([String]).splitStr "gggggggeeeeetttttt" should return ["ggggggg","eeeee","tttttt"]Data.List already provides such a function, it's named group.length for that.head. Eg. head "abc" yields 'a'.show, which turns most stuff into a string. Our helper looks like this: makeRepetitions string = head string : show (length string). : aka cons adds an element to the front of a list.map for that. map applies a function to a list of values and returns the list of resultsconcat for this. Actually, we can combine (4) and (5) using concatMap. This function maps a function to a list of values and concats the results - just as we want it.Now, your code looks like this:
import Data.List
runlength :: String -> String
runlength string = concatMap makeRepetitions (group string)) where
makeRepetitions string = head string : show (length string)
Because that much brackets are annoying, Haskellers often use ..The dot combines two functions to create a new one. You can think of f = functionA . functionB is equal to f x = functionA (functionB x). Using the dot, we can reformat the program a bit:
import Data.List
runlength :: String -> String
runlength = concatMap makeRepetitions . group where
makeRepetitions string = head string : show (length string)
IMO, This representation is more readable. You can see runlength as a pipeline. First apply group, then we use concatMap to map makeRepetitions onto the input and concat the results.
Abuse of arrows and pointfree :)
f = group >>> concatMap (head &&& (show . length) >>> uncurry (:))
And here's with applicative:
f = concatMap ((:) <$> head <*> (show . length)) . group