2011-08-18 105 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

我喜歡這個!當你只對某些字符的頻率感興趣而不是輸入字符串中的所有字符時,這非常有用。井井有條。 –