Trying to determine how to count the occurrences of a char
is a string
. I was it to be stored in a list [char,count]
.
countChars :: String -> [(Char, Int)]
I'm new and learning Haskell so any help is much appreciated.
to give you a taste
> (map (head &&& length) . group . sort) "asdfasdfaeadf"
[('a',4),('d',3),('e',1),('f',3),('s',2)]
after bunch or imports.
You can easily define your head &&& length, if that syntax is unfamiliar.
> head_and_length x = (head x, length x)
group can be written recursively
group [] = []
group (x:xs) = (x:ys) : group zs
where (ys,zs) = (takeWhile (==x) xs, dropWhile (==x) xs)
take as many matching elements as possible and recursively apply on the remaining elements until nothing left. Note that this definition requires same elements to be contiguous, that's why a sort is required.
Writing a complex function is one piece is not recommended, it's better to implement small features separately (and perhaps use the existing functions) which can be independently tested and create a composition of these as a final solution.
This isn't going to be helpful, but it is going to be fast. The trick is to use an IntMap
, a very efficient representation of maps with Int
keys, to store how many of each character have been seen. We're using characters for keys, so we start by creating a CharMap
type wrapping up an IntMap
and writing some functions that wrap up their IntMap
equivalents.
import Data.Foldable (Foldable, foldl')
import Control.Applicative ((<|>))
import qualified Data.IntMap.Strict as IM
import Data.IntMap (IntMap)
-- Strict version of Data.Bifunctor.first
first :: (a -> a') -> (a, b) -> (a', b)
first f (a, b) = (f a, b)
newtype CharMap a = CharMap (IntMap a)
emptyCM :: CharMap a
emptyCM = CharMap (IM.empty)
toAssocAsc :: CharMap a -> [(Char, a)]
toAssocAsc (CharMap m) = map (first toEnum) (IM.toAscList m)
alter :: (Maybe a -> Maybe a) -> Char -> CharMap a -> CharMap a
alter f c (CharMap m) = CharMap $ IM.alter f (fromEnum c) m
That was a bit annoying, but rather mechanical. Here's the main event. We toss characters into a CharMap
, keeping them mapped to their counts, and then convert the map to an association list when we're done.
countCharacterOccurrences ::
Foldable t => t Char -> [(Char, Int)]
countCharacterOccurrences = toAssocAsc . foldl' go emptyCM
where
go m c = alter (\curr -> fmap (+1) curr <|> Just 1) c m
来源:https://stackoverflow.com/questions/36046419/count-occurrences-of-character-in-a-string-haskell