2011-08-18 115 views
17

如何计算字符串中字符的频率然后以表格的形式输出它们?如何在Haskell中查找字符串中的字符频率?

例如,如果我输入单词“幸福”的结果将是

h 1 
a 1 
p 2 
y 1 

如果能在ASCII顺序进行排序也将是辉煌的。

我知道我需要使用计数功能,任何其他提示将不胜感激。

编辑:所有的答案都辉煌,只是我在哈斯克尔这样的初学者,我不真正了解自己在做什么。

回答

9

有可能是一些短,但这个工程:

Prelude> import Data.List 
Prelude Data.List> map (\x -> (head x, length x)) $ group $ sort "happy" 
[('h',1),('a',1),('p',2),('y',1)] 
+1

你必须先解决输入支付像'“糊状”'案件其中'p'的出现不是连续的。 – hammar

+0

谢谢,修正。 :-) –

+2

并注意'(\ x - >(head x,length x))== head &&& length',其中'(&&&)'来自'Control.Arrow'。 – Conal

39

最简单的解决方法是使用一个Data.Map到中间映射存储从字符频率。然后您可以使用fromListWith轻松构建计数。由于Data.Map已排序,因此您可以免费获得ASCII码。

λ> :m + Data.Map 
λ> let input = "happy" 
λ> toList $ fromListWith (+) [(c, 1) | c <- input] 
[('a',1),('h',1),('p',2),('y',1)] 

所以这里发生了什么?

的想法是使用字符键和频率,值,以建立一个Data.Map(树地图)。

首先,我们将输入字符串与每个字符的元组作一个1来表示一个事件。

λ> [(c, 1) | c <- input] 
[('h',1),('a',1),('p',1),('p',1),('y',1)] 

接下来,我们使用fromListWith通过重复地将每个键 - 值对成映射建立从这些键 - 值对的有序映射。我们还给它一个函数,当一个键已经在地图上时,它将被使用。在我们的例子中,我们使用(+),这样当一个角色被多次查看时,我们会将计数添加到现有总和中。

最后,我们使用toList将地图转换回键值元组列表。

+0

我觉得我很愚蠢,但这是一个程序吗?如果这是一个愚蠢的问题,我在哈斯克尔这样一个小菜很抱歉。 – Hagrid123

+0

@ Hagrid123:这些例子取自GHCi(解释器)会话,与您在Haskell源文件中找到的略有不同。例如'let'用于顶层绑定,':m'可用于导入模块。 – hammar

+2

对于记录,GHCi提示符的标记是'>'字符。当你第一次启动ghci时,你可能会看到'Prelude>';注意范围中的模块在提示中列出。哈马尔的ghci提示似乎已经过时了。 –

4

func xs = map (\a -> (head a, length a)) $ group $ sort xs

+0

'groupBy(\ xy - > x == y)'与'group'相同 – newacct

+0

是的,我意识到我发布它的那一刻。 :) – Marii

0

我会scetch的解决方案分步实施。使用标准功能可以缩短解决方案的时间。

你想要一个排序结果,因此

result = sort cs 
    where 

CS将元组,其中第一个元素是字符,第二个元素的列表是它出现的次数。

 cs = counts "happy" 
     counts [] = [] 
     counts (c:cs) = (c, length otherc + 1) : counts nonc where 
      (otherc, nonc) = partition (c==) cs 

就是这样。

有趣的是,计数适用于任何支持==运算符的项目列表。

0
import Data.Array (Ix, accumArray, assocs) 

eltDist :: (Bounded a, Ix a, Eq b, Num b) => [a] -> [(a, b)] 
eltDist str = filter ((/=0) . snd) $ 
    assocs (accumArray (+) 0 (minBound, maxBound) [(i, 1) | i <- str]) 

“minBound”和“maxBound”将取决于为i推断的类型的范围。对于字符它将是0 - 1,114,111,这是奢侈的,但不是不可能的。如果您计算Unicode字符,这将特别方便。如果你只对ASCII字符串感兴趣,那么(0,255)就可以。数组的一个好处是它们可以被任何可以映射到整数的类型索引。请参阅1x

assocs将索引和计数从数组中排列成对的列表并对未使用的列表进行过滤处理。

3

使用列表理解,不需要任何导入或排序。

[ (x,c) | x<-['A'..'z'], let c = (length.filter (==x)) "happy", c>0 ] 

结果:

[('a',1),('h',1),('p',2),('y',1)] 

上面是过滤和重写(仅适用于字符计数> 0):

[(x,(length.filter (==x)) "happy") | x<-['A'..'z']] 

说明:

  • 做一个列表与给定字符(A..z)匹配的所有字符。
  • 对于每个角色,算上这个列表(==长度)
  • 将这个数量在一个元组与角色
+0

我喜欢这个!当你只对某些字符的频率感兴趣而不是输入字符串中的所有字符时,这非常有用。井井有条。 –