【问题标题】:WordCount in HaskellHaskell 中的字数统计
【发布时间】:2020-11-18 18:36:17
【问题描述】:

我正在计算数量 文本中每个单词的出现次数 然后将其表示为元组列表。

我尝试过使用累加器 我已经尝试过使用 concat 和过滤。发生了什么 问题是我不确定如何处理列表中的列表。

我不确定如何从这里继续,我尝试在参数上使用过滤器 (x /=) 调用函数 wordCountt,但由于某种原因无法运行。非常感谢这里的一些指导。

干杯

type Document = [Sentence]
type WordTally = [(String, Int)]

wordCountt :: Document -> WordTally
wordCountt [] = []
wordCountt [(x:xs), ys] = [(x, length (filter (x ==) (concat [(x:xs), ys])))] ++ wordCountt [xs, ys]```



```wordCountt [["a", "rose", "is", "a", "rose"],["but", "so", "is", "a", "rose"]]
[("a",3),("rose",3),("is",2),("a",2),("rose",2)*** Exception: CompLing.hs:(60,1)-(61,100): Non-exhaustive patterns in function wordCountt```

【问题讨论】:

  • 您可以使用concat 摆脱列表列表。但是,尽管如此,我认为您在 single 函数中执行所有操作会使问题变得更加复杂。分开你的顾虑。编写可以合并两个WordTallys 的辅助函数。您可能还想看看Map,它是一个字典类型。
  • 这里还有一个问题是[(x:xs), ys] 模式。这意味着您只匹配长度为 two 的列表。因此,如果列表包含一个或三个或更多元素,则会引发错误。您应该使用(x:xs) : ys 模式来匹配非空列表。

标签: list haskell filter


【解决方案1】:

为了制作直方图,我一直很喜欢Map.fromListWith

import qualified Data.Map.Strict as Map
import           Data.Map (Map)

histogram :: Ord a => [a] -> Map a Int
histogram xs = Map.fromListWith (+) (zip xs (repeat 1))

它的工作方式:

> zip (words "a rose is a rose") (repeat 1)
[("a",1),("rose",1),("is",1),("a",1),("rose",1)]

> Map.fromListWith (+) [("hello",1),("hello",1)]
fromList [("hello",2)]

> Map.fromListWith (+) [("a",1),("rose",1),("is",1),("a",1),("rose",1)]
fromList [("a",2),("is",1),("rose",2)]

> histogram (words "a rose is a rose")
fromList [("a",2),("is",1),("rose",2)]

所以当同一个单词出现在两个(单词,计数)元组中时,计数得到+'ed。

【讨论】:

  • zip xs (repeat) 等价于map (,1) xs(带有TupleSections 扩展名)。当然,就性能而言(很多)并不重要:)
  • 对。而repeat 1 等价于[1,1..]。我选择了语法较少的那个。 :)
【解决方案2】:

我认为你试图在一个函数中做太多太多。这意味着该函数更难实现、调试,也许最重要的是,让自己相信它是有效的。

我们可以把函数分成两部分:

  1. 将给定元素添加到WordTally 的函数;和
  2. 一个枚举文档所有单词并不断更新WordTally的函数。

更新函数如下所示:

addWord :: WordTally -> String -> WordTally
addWord = …

因此函数采用WordTallyString。如果String ready 是 wordcount 的“成员”,则增加计数,否则我们将其加一。您可以为此使用显式递归。

那么wordCountt 就是一个折叠模式。事实上,我们可以利用:

wordCountt :: Document -> WordTally
wordCountt d = foldl addWord [] (concat d)

或更短:

wordCountt :: Document -> WordTally
wordCountt = foldl addWord [] . concat

因此,我们从一个空列表作为WordTally 开始,每次从文档列表的列表中添加一个元素并相应地更新WordTally,直到我们到达单词的末尾。

然而这不会很有效,因为更新WordTally 列表,每个单词需要 O(n),因此这会变成 O(n2 ) 算法。例如,您可以(稍后)查看Map,这是一个可以在O(log n)中插入/更新的容器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-04
    • 2015-01-22
    • 2012-06-29
    • 2023-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多