计算字符串中字符的出现次数(Haskell)

时间:2012-08-10 15:44:12

标签: string haskell

  

可能重复:
  How to find the frequency of characters in a string in Haskell?

给定一个输入字符串,我希望计算每个字符的出现次数。我有两种方法(在非常伪的伪代码中):

For each character in the "alphabet"
  traverse the string and increment a counter when the character is found

我相信我可以很容易地在Haskell中实现这一点。我的第二个想法有点棘手:

For each character in the string
  increment a counter and store it in a map (or similar data structure)

我对Haskell中的数据结构缺乏经验,所以第二个解决方案比第一个解决方案更令人生畏。但是,我当然希望通过实现自己的数据结构或使用内置库中的内容来学习更多内容。

有没有人对我该如何处理有任何建议?

4 个答案:

答案 0 :(得分:4)

Data.Map是关联数组的标准。我认为它位于containers包中并且有很好的文档记录。 insertWith函数可能对此问题特别感兴趣 - 它允许您插入新的键和值,但也提供一个函数(您希望使用+)将值与值组合在地图中,如果有的话。

答案 1 :(得分:2)

在Haskell中,=符号就像在数学中一样用于定义方程式。惯用的Haskell避免了变异(例如“增加计数器”),而是鼓励使用纯函数的解决方案。但是,使用ST,您可以像使用任何其他语言一样使用变异编写算法。

考虑确定单个字符在字符串中出现的次数的任务。 根据你的英文描述

  

遍历字符串并在找到字符时递增计数器

Python实现将是

def count(c, s):
  i = 0
  for c0 in s:
    if c == c0:
      i += 1
  return i

使用ST我们可以编写完全相同的代码,虽然它稍微冗长一点,因为可变变量的所有创建,读取和写入都是明确命名的:

import Control.Monad (when, forM_)
import Control.Monad.ST (runST)
import Data.STRef

count :: Char -> String -> Int
count c s = runST $ do     -- def count(c, s):
  i <- newSTRef 0          --   i = 0
  forM_ s $ \c' -> do      --   for c0 in s:
    when (c == c') $ do    --     if c == c0:
      modifySTRef i (+1)   --       i += 1
  readSTRef i              --   return i

正如我之前所说,这不是惯用的Haskell,但是当你已经有一个使用变异的命令式算法时,我认为没有理由避开ST。由于变异已本地化为函数,并且无法从外部观察到,因此我们可以使用runST隐藏实现细节并提供纯接口Char -> String -> Int

答案 2 :(得分:1)

我建议:

  • 阅读folds。折叠是处理列表的函数式编程中非常常见的模式。

  • 查看一些Haskell libraries(警告:它们非常广泛并需要一段时间才能完成 - 但绝对值得付出努力)。通常可以通过将一些预定义的函数(例如,sort / group / map / length)粘合在一起来找到解决诸如你的问题的方法。本练习让您更熟悉库,Haskell语法和编码风格,FP以及通过合成解决问题。

答案 3 :(得分:0)

我假设Haskell中可能存在一个函数(寻找(Eq a, Integral i) => [a] -> a -> i),但这可以很容易地表达为折叠

count a = foldr (\x sum -> if x == a then sum+1 else sum) 0

http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:foldr

对于地图,请查找Data.Map模块。 (编写一个简单的基于列表的地图也很容易)