【问题标题】:Count word frequency using map使用地图计算词频
【发布时间】:2015-06-16 14:49:20
【问题描述】:

这是我第一次在 C++ 中实现地图。所以给定一个带有文本的字符数组,我想计算每个单词在文本中出现的频率。我决定实现 map 来存储单词并比较后面的单词并增加一个计数器。 以下是我目前写的代码。

  const char *kInputText = "\
  So given a character array with text, I want to count the frequency of
  each word occurring in the text.\n\
  I decided to implement map to store the\n\
  words and compare following words and increment a counter.\n";      

  typedef struct WordCounts
  {
       int wordcount;
  }WordCounts;

  typedef map<string, int> StoreMap;

  //countWord function is to count the total number of words in the text.
  void countWord( const char * text, WordCounts & outWordCounts )
  {
       outWordCounts.wordcount = 0;
       size_t i;
       if(isalpha(text[0]))
            outWordCounts.wordcount++;
       for(i=0;i<strlen(text);i++)
       {
            if((isalpha(text[i])) && (!isalpha(text[i-1])))
                 outWordCounts.wordcount++;
       }
       cout<<outWordCounts.wordcount;
  }

  //count_for_map() is to count the word frequency using map.
  void count_for_map(const char *text, StoreMap & words)
  {
       string st;
       while(text >> st)
            words[st]++;
  }

  int main()
  {
       WordCounts wordCounts;
       StoreMap w;
       countWord( kInputText, wordCounts );
       count_for_map(kInputText, w);
       for(StoreMap::iterator p = w.begin();p != w.end();++p)
       {
             std::cout<<p->first<<"occurred" <<p->second<<"times. \n";
       }
       return 0;
  }



  Error: No match for 'operator >>' in 'text >> st'
  I understand this is an operator overloading error, so I went ahead and
  wrote the following lines of code.
  //In the count_for_map()
       /*istream & operator >> (istream & input,const char *text)
       {
             int i;
             for(i=0;i<strlen(text);i++)
                 input >> text[i];
             return input;
       }*/
  Am I implementing map in the wrong way?

【问题讨论】:

  • 您可能还应该在代码上方的正文中描述您的错误,因为目前读者必须筛选您的代码才能找出您遇到的问题。

标签: c++ dictionary stl operator-overloading


【解决方案1】:

&gt;&gt; 左侧没有 const char* 过载。

textconst char*,而不是 istream,因此您的重载不适用(并且重载 1: 是错误的,而 2: 已存在于标准库中)。

你想用更合适的std::istringstream,像这样:

std::istringstream textstream(text);
while(textstream >> st)
    words[st]++;

【讨论】:

  • +1,不过是次要的挑剔:有“文本”和“文本”。这将被视为字符串中的单独单词,因此您需要先删除标点符号。
  • 这很完美!但是,当我尝试将包含迭代器的 for 循环从 main() 移动到 count_for_map() 时,我收到一条错误消息,提示“w”未初始化。但是我已经在 main() 中初始化了 w。
  • @user2948246 赋予事物相同的名称并不会使它们成为相同的事物。如果您在main 中声明了一个变量“w”,在另一个函数中声明了一个“w”,则它们是完全不同的独立变量。
  • 我的错误问题。所以就像我说的,我将包含迭代器的 for 循环转移到 count_for_map() 中。但是我注意到,当我运行它时,text_array 中的文本会打印出介于两者之间的垃圾值,并且单词频率的计数被搞砸了,而不是当带有迭代器的 for 循环是 main() 和输出时是完美的。我想移动 for 循环的原因是因为我想以一定的频率打印单词。 for(StoreMap::iterator p = w.begin();p != w.end();++p) { std::cout&lt;&lt;p-&gt;first&lt;&lt;" occurred " &lt;&lt;p-&gt;second&lt;&lt;" times. \n"; }
【解决方案2】:

如果您使用现代 C++ 语言,那么生活会变得轻松得多。

首先。使用std::map 是正确的方法。

这是一种或多或少的标准方法来计算容器中的东西。

我们可以使用std::mapstd::unordered_map 之类的关联容器。在这里,我们将“键”(在本例中为要计数的“单词”)与一个值(在本例中为特定单词的计数)相关联。

幸运的是,地图有一个非常好的索引运算符[]。这将查找给定的键,如果找到,则返回对该值的引用。如果未找到,它将使用密钥创建一个新条目并返回对新条目的引用。因此,在机器人案例中,我们将获得对用于计数的值的引用。然后我们可以简单地写:

std::unordered_map<std::string, unsigned int> counter{};
counter[word]++;

但是如何从字符串中获取单词。字符串就像一个包含元素的容器。在 C++ 中,许多容器都有迭代器。特别是对于字符串,有一个专用的迭代器,它允许在std::string 中迭代模式。它被称为std::sregex_token_iterator 并描述为here.。该模式以std::regex 的形式给出,这将为您提供极大的灵活性。

而且,因为我们有如此出色且专用的迭代器,我们应该使用它!

将所有东西粘在一起将提供一个非常紧凑的解决方案,代码行数最少。

请看:

#include <iostream>
#include <string>
#include <regex>
#include <map>
#include <iomanip>

const std::regex re{ "\\w+" };
const std::string text{ R"(So given a character array with text, I want to count the frequency of 
each word occurring in the text. 
I decided to implement map to store the
words and compare following words and increment a counter.")" };


int main() {
    std::map<std::string, unsigned int> counter{};

    for (auto word{ std::sregex_token_iterator(text.begin(),text.end(),re) }; word != std::sregex_token_iterator(); ++word)
        counter[*word]++;

    for (const auto& [word, count] : counter) 
        std::cout << std::setw(20) << word << "\toccurred\t" << count << " times\n";
}

【讨论】:

    猜你喜欢
    • 2019-11-22
    • 2020-09-11
    • 1970-01-01
    • 2021-02-28
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 2020-06-24
    • 2019-06-25
    相关资源
    最近更新 更多