【问题标题】:Counting the appearance of words in a vector and listing those in a list, C++计算向量中单词的出现并列出列表中的单词,C++
【发布时间】:2020-07-19 00:59:48
【问题描述】:

我有一个包含单独单词的 cpp 向量,我需要计算一个单词使用列表出现的次数。我尝试遍历列表,但在比较两个 STL 容器时失败,无论以下单词是否已经在我的列表中。如果没有,我想将该单词添加到我的列表中,外观为 1。我有一个结构可以计算单词在文本中出现的次数。 以下代码返回一个单词和数字列表,但不是每个都在我的向量中,我不明白为什么。

struct counter{
    string word;
    int sum = 1;
    counter(){};
    counter(string word): word(word){};
};

list<counter> list_count(vector<string> &text){
    list<counter> word_count;
    list<counter>::iterator it = word_count.begin();
    for(string t:text){
        if(it != word_count.end()){
            it -> sum++;
        } else {
            word_count.push_back(counter(t));
        }
        ++it;
    }
    return word_count;
}

提前谢谢你。

【问题讨论】:

  • 您需要使用list?只是要求从可能的答案中消除一些容易得到的结果。 std::map 让频率计数变得简单。
  • 在上面的代码中it != word_count.end() 永远不会是真的。
  • 是的,我需要同时使用列表和地图。我管理了地图版本,确实更容易。
  • @blntms 你应该在你的列表中使用std::find_if
  • @john 好点

标签: c++ list vector iterator counter


【解决方案1】:
list<counter> list_count(const vector<string>& text) {
    list<counter> word_count;
    for (const string& t : text) {
        auto it = std::find_if(word_count.begin(), word_count.end(), 
            [&](const counter& c){ return c.word == t; });
        if (it != word_count.end()) {
            it -> sum++;
        } else {
            word_count.push_back(counter(t));
        }
    }
    return word_count;
}

未经测试的代码。

【讨论】:

  • 谢谢@john。问题仍然存在,我收到“find_if 不是 std 成员”的错误,这很奇怪
  • @blntms 你需要#include &lt;algorithm&gt;std::find_if
  • @john 是的,忘记了,它现在正在工作。谢谢!
  • @Remy Lebeau 是的,我认为它已经包含在内。也非常感谢你!
【解决方案2】:

您实际上根本没有搜索std::list。在通过std::vector 的每次循环迭代中,您需要从前到后搜索整个std::list,例如:

#include <string>
#include <list>
#include <vector>
#include <algorithm>

using namespace std;

struct counter {
    string word;
    int sum = 1;
    counter(const string &word): word(word) {}
};

list<counter> list_count(const vector<string> &text) {
    list<counter> word_count;
    for(const string &t: text) {
        // perform an actual search here!
        list<counter>::iterator it = find_if(
            word_count.begin(), word_count.end(),
            [&](counter &c){ return (c.word == t); }
        );
        if (it != word_count.end()) {
            it->sum++;
        } else {
            word_count.emplace_back(t);
        }
    }
    return word_count;
}

Live Demo

话虽如此,std::list 对于元素计数来说是一个糟糕的解决方案。更好的解决方案是使用std::(unordered_)map 代替(除非您需要保留找到的单词的顺序,这两个都不会这样做),例如:

#include <string>
#include <map>
#include <vector>

using namespace std;

map<string, int> list_count(const vector<string> &text) {
    map<string, int> word_count;
    for(const string &t: text) {
        word_count[t]++;
    }
    return word_count;
}

Live Demo(使用std::map

Live Demo(使用std::unordered_map

【讨论】:

    【解决方案3】:

    您正在尝试使用低效的方法。标准类模板列表不能随机访问其元素。每个新元素都附加到列表的末尾。要查找一个元素是否已经存在于列表中,它的元素是按顺序遍历的。

    使用标准容器 std::map 会更有效。此外,在这个容器中,单词将被排序。

    例如你可以声明

    std::map<std::string, size_t> counters;
    

    不过,如果你想使用列表,那么函数可以如下面的演示程序所示。

    #include <iostream>
    #include <string>
    #include <list>
    #include <vector>
    #include <iterator>
    #include <algorithm>
    
    struct counter
    {
        std::string word;
        size_t n = 0;
        counter() = default;
        counter( const std::string &word ): word( word ), n( 1 ){}
    };
    
    std::list<counter> list_count( const std::vector<std::string> &text )
    {
        std::list<counter> word_count;
    
        for ( const auto &s : text )
        {
            auto it = std::find_if( std::begin( word_count ), std::end( word_count ),
                                    [&s]( const auto &c ) { return c.word == s; } );
    
            if ( it == std::end( word_count ) )
            {
                word_count.push_back( s );
            }
            else
            {
                ++it->n;
            }
        }
    
        return word_count;
    }
    
    int main() 
    {
        std::vector<std::string> v { "first", "second", "first" };
    
        auto word_count = list_count( v );
    
        for ( const auto &c : word_count )
        {
            std::cout << c.word << ": " << c.n << '\n';
        }
    
        return 0;
    }
    

    它的输出是

    first: 2
    second: 1
    

    注意struct counter的定义是多余的。您可以改用标准类 std::pair。给你。

    #include <iostream>
    #include <string>
    #include <utility>
    #include <list>
    #include <vector>
    #include <iterator>
    #include <algorithm>
    
    std::list<std::pair<std::string, size_t>> list_count( const std::vector<std::string> &text )
    {
        std::list<std::pair<std::string, size_t>> word_count;
    
        for ( const auto &s : text )
        {
            auto it = std::find_if( std::begin( word_count ), std::end( word_count ),
                                    [&s]( const auto &p ) { return p.first == s; } );
    
            if ( it == std::end( word_count ) )
            {
                word_count.emplace_back( s, 1 );
            }
            else
            {
                ++it->second;
            }
        }
    
        return word_count;
    }
    
    int main() 
    {
        std::vector<std::string> v { "first", "second", "first" };
    
        auto word_count = list_count( v );
    
        for ( const auto &p : word_count )
        {
            std::cout << p.first << ": " << p.second << '\n';
        }
    
        return 0;
    }
    

    如果使用std::map,那么函数看起来很简单。

    #include <iostream>
    #include <string>
    #include <vector>
    #include <map>
    
    std::map<std::string, size_t> list_count( const std::vector<std::string> &text )
    {
        std::map<std::string, size_t> word_count;
    
        for ( const auto &s : text )
        {
            ++word_count[s];
        }
    
        return word_count;
    }
    
    int main() 
    {
        std::vector<std::string> v { "first", "second", "first" };
    
        auto word_count = list_count( v );
    
        for ( const auto &p : word_count )
        {
            std::cout << p.first << ": " << p.second << '\n';
        }
    
        return 0;
    }
    

    只有在对字符串向量进行排序的情况下,使用列表才会有效。

    这是一个演示程序。

    #include <iostream>
    #include <string>
    #include <list>
    #include <vector>
    
    struct counter
    {
        std::string word;
        size_t n = 0;
        counter() = default;
        counter( const std::string &word ): word( word ), n( 1 ){}
    };
    
    std::list<counter> list_count( const std::vector<std::string> &text )
    {
        std::list<counter> word_count;
    
        for ( const auto &s : text )
        {
            if ( word_count.empty() || word_count.back().word != s )
            {
                word_count.push_back( s );          
            }
            else
            {
                ++word_count.back().n;
            }
        }
    
        return word_count;
    }
    
    int main() 
    {
        std::vector<std::string> v { "A", "B", "B", "C", "C", "C", "D", "D", "E" };
    
        auto word_count = list_count( v );
    
        for ( const auto &c : word_count )
        {
            std::cout << c.word << ": " << c.n << '\n';
        }
    
        return 0;
    }
    

    它的输出是

    A: 1
    B: 2
    C: 3
    D: 2
    E: 1
    

    【讨论】:

      猜你喜欢
      • 2013-12-25
      • 1970-01-01
      • 1970-01-01
      • 2021-02-05
      • 1970-01-01
      • 1970-01-01
      • 2021-10-15
      • 2015-05-31
      • 2011-08-04
      相关资源
      最近更新 更多