Reputation: 31
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.
Upvotes: 3
Views: 1424
Reputation: 4896
Abuse of arrows and pointfree :)
f = group >>> concatMap (head &&& (show . length) >>> uncurry (:))
And here's with applicative:
f = concatMap ((:) <$> head <*> (show . length)) . group
Upvotes: 1
Reputation: 1115
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
Upvotes: 13
Reputation: 1455
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
Upvotes: 7
Reputation: 93034
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.
Upvotes: 3