Count occurrences of character in a string Haskell [closed]

♀尐吖头ヾ 提交于 2019-12-01 14:27:43

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
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!