【问题标题】:How do I print the frequency of each word in the given input string using two vectors?如何使用两个向量打印给定输入字符串中每个单词的频率?
【发布时间】:2021-10-26 07:42:22
【问题描述】:

这是我尝试将字符串拆分为单词然后继续前进的方法,但这不起作用。 例如,输入是:hey hi Mark hi mark 那么输出应该是: 嘿-1 嗨-2 标记-1 嗨-2 标记-1

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main() 
{
    vector<vector<string> > strs;
    string str;
    cout<<"Enter your strings"<<endl;
    getline(cin, str);
    int len=str.length();
    int j=0;
    string s="";
    for(int i=0; i<len; i++){
      s+=str[i];
      if(str[i+1]==' ' || i+1==len){
        strs[0][j]=s;
        s="";
        j++;
        i++;
      }
    }
    strs[0][j]="NULL";
    int freq;
    vector<int> frequency;
    for(int n=0; strs[0][n]!="NULL" ;n++){
      freq=1;
      for(int m=0; strs[0][m]!="NULL"; m++){
        if(strs[0][n]==strs[0][m]){
          freq++;
        }
        frequency.push_back(freq);
      }
    }
    for(int x=0; strs[0][x]!="NULL"; x++){
      cout<<strs[0][x]<<" - "<<frequency[x]<<endl;
    }
    return 0;
}

【问题讨论】:

  • 经典方法是使用std::unordered_map&lt;std::string, uint&gt; histogram;,并在每次出现时将其递增histogram["word"]++;

标签: c++ string vector


【解决方案1】:

在您的代码中,您尝试通过其索引访问字符串元素,这有时会引发分段错误。为了解决您的问题,我想出了下面提到的解决方案。

#include <iostream>
#include <string>
#include <map>

/* getWordFrequency : function with return type std::map<std::string, int>
   Param1: Input string 
   Param2: Default delimiter as " "(void space).
*/ 
std::map<std::string, int> getWordFrequency(const char *input_string, char c = ' ')
{
    // Container to store output result
    std::map<std::string, int> result;

    // Iteration loop
    do{
        // Iteration pointer to iterate Character by Character 
        const char *begin = input_string;
        // Continue loop until delimeter or pointer to self detects
        while(*input_string != c && *input_string){
            // Jump to next character
            input_string++;
            }
            // Iterator for output result container
            std::map<std::string, int>::iterator finder = result.find(std::string(begin, input_string));
            // Find element using iterator
            if(finder != result.end()){
                // Element already present in resultunt map then increment frequency by one
                finder->second += 1;
            } else {
                // If no element found then insert new word with frequency 1
                result.insert(std::pair<std::string, int>(std::string(begin, input_string),1));
            }
    } while (0 != *input_string++); // Continue till end of string
    return result;
}

int main() 
{
    // Your string
    std::string input_string = "hey hi Mark hi mark";
    // Container to catch result
    std::map<std::string, int> frequency = getWordFrequency(input_string.c_str());
    // Printing frequency of each word present in string
    for (auto element : frequency){
        std::cout << element.first << "-" << element.second << std::endl;
    }
    return 0;
}

【讨论】:

  • 我想到了这种方法,但问题仍然是我必须使用矢量来解决这个问题。使用 stringstream 获取向量中的输入可以帮助解决我猜的问题。
【解决方案2】:

所以,不幸的是,我认为您使用 2 std::vectors 的方法是错误的。您还没有完全理解charstd::string 之间的区别。

你需要了解一下。

有一种或多或少的标准方法来计算容器中的某些内容,例如字符串或一般情况。

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

幸运的是,地图有一个非常好的索引运算符[]。这将查找给定的键,如果找到,则返回对该值的引用。如果没有找到,那么它将使用密钥创建一个新条目并返回对新条目的引用。因此,在这两种情况下,我们都会获得对用于计数的值的引用。然后我们可以简单地写:

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

就是这样。不需要更多。请看:

#include <iostream>
#include <string>
#include <sstream>
#include <unordered_map>

int main() {
    // Our test String
    std::string text{"hey hi Mark hi mark"};
    
    // Here, we will store the result of the counting
    std::unordered_map<std::string, unsigned int> counter;
    
    // Now count all words. This one line does all the counting
    for (std::istringstream iss{text}; iss >> text; counter[text]++);
    
    // Show result to user
    for (const auto& [word, count] : counter) std::cout << word << '-' << count << ' ';
}

似乎拆分字符串对您来说有些困难。此外,这里还有许多可能的解决方案。

更复杂和更高级的解决方案之一是使用std::sregex_token_iterator。有了它,您可以轻松地迭代字符串中的模式(由 std::regex 描述)。

最终代码看起来几乎相同,但结果会更好,因为例如可以排除标点符号。

例子:

#include <iostream>
#include <string>
#include <unordered_map>
#include <regex>
#include <iterator>

using Iter = std::sregex_token_iterator;
const std::regex re{R"(\w+)"};

int main() {
    // Our test String
    std::string text{"hey hi Mark, hi mark."};
    
    // Here, we will store the result of the counting
    std::unordered_map<std::string, unsigned int> counter;
    
    // Now count all words. This one line does all the counting
    for (Iter word(text.begin(), text.end(), re); word != Iter(); counter[*word++]++);
    
    // Show result to user
    for (const auto& [word, count] : counter) std::cout << word << '-' << count << ' ';
    
}

【讨论】:

    猜你喜欢
    • 2016-12-06
    • 2015-07-30
    • 1970-01-01
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    相关资源
    最近更新 更多