C++ 计数图

C++ Counting Map

最近我在处理我确定是一个非常普遍的问题,基本上可以归结为以下几点:

给定一个长文本,计算每个单词在文本中出现的频率。

我能够使用 std::unordered_map 解决这个问题。然而,这变得非常难看,对于文本中的每个单词,如果已经遇到过,我必须进行查找、删除,然后重新插入地图并增加值。

我知道还有其他方法可以做到这一点,例如在原始 array/vector 之上使用散列函数并在那里增加值,但我想知道是否有更优雅的方法来解决这个问题问题,如 STL 组件或函数。这将具有与 Pythons Counter 集合类似的界面。

我知道 C++ 就是 C++ 我真的不能指望总是为我实现如此高层次的概念,但只是想知道你们是否有任何新知识(或者至少你们的谷歌搜索技能优于我的)哪个可以使我的代码更好一些。

我不太确定为什么 std::unordered_map(或只是 std::map)会涉及很多复杂性。我会写这样的代码:

std::unordered_map<std::string, int> words;

std::string word;
while (word = getword(input))
   ++words[word];

不需要任何类型的find/erase/reinsert。

如果不清楚 how/why 这有效:如果 none 还存在于地图中,operator[] 将为一个值创建一个条目。关联值将是指定类型的值初始化对象,在 int(或类似)的情况下将为零。然后我们每次遇到这个词时都会增加它。

另一种解决方案:

std::multiset<std::string> m;
for (auto w: words) m.insert(w);

m.count("some word");

优点是不用依赖'trick'和operator[],代码可读性更好。

EDIT:正如 Kerrek 在评论中指出的那样,此解决方案速度较慢。 multiset 存储您插入的所有元素,即使它们被认为是相等的(它们可能在 operator== 未检查的某些方面仍然不同)。与 unordered_map<std::string, int> 相比,这会导致显着的开销,后者只需将每个单词存储一次。

(附带说明,在我的机器上使用地图解决方案处理莎士比亚全集大约需要 0.33 秒,而使用多集解决方案则需要 0.78 秒。)