【问题标题】:How can I push_back a map<string, int> into a vector<map<string, int>> via an iterator?如何通过迭代器将 map<string, int> 推回 vector<map<string, int>> ?
【发布时间】:2023-03-15 11:04:01
【问题描述】:

我目前正在学习 Accelerated C++ (Koening/Moo) 一书,但其中一个练习有问题。任务是编写一个程序,将一些单词序列作为输入,然后将其存储在map&lt;string, int&gt; 中。字符串是输入的单词,关联的int 是每个单词出现的次数。然后,您必须按单词出现的次数对单词进行排序;也就是说,按值而不是键。您不能按值对地图进行排序,因此我尝试将元素复制到向量中,而我打算使用谓词对其进行排序。不幸的是,我得到的只是一个充满 g++ 错误的屏幕。它们似乎来自同一个地方 - 将我的地图元素放入我的矢量中,我尝试这样做:

int main()
{
    map<string, int> counters;

    cout << "Enter some words followed by end-of-file (ctrl-d): ";
    string word;
    while (cin >> word)
       ++counters[word];

    // Maps cannot be sorted by values, so pass the elements of counters to a vector.
    vector<map<string, int> > vec_counters;

    map<string, int>::const_iterator it = counters.begin();
    while (it != counters.end()) {
       vec_counters.push_back(*it);
       ++it;
    }
}

这显然只是第一部分,但我什至无法编译。我收到以下错误:

32:31: 错误:没有匹配函数调用 std::vector, int> >::push_back(const std::pair, int>&)’ /usr/include/c++/4.5/bits/stl_vector.h:741:7:注意:候选是:void std::vector<_tp _alloc>::push_back(const value_type&) [with _Tp = std::map, int>, _Alloc = std::allocator, int> >, value_type = std::map, int>]

我做错了什么?

【问题讨论】:

  • 这听起来像是 Boost.Bimap 的工作!

标签: c++ dictionary vector iterator push-back


【解决方案1】:

我很确定您不是在寻找地图矢量:

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

using namespace std;
int main()
{
    map<string, int> counters;

    cout << "Enter some words followed by end-of-file (ctrl-d): ";
    string word;
    while (cin >> word)
       ++counters[word];

    vector<std::pair<string, int> > vec(counters.begin(), counters.end());
}

【讨论】:

  • @KerrekSB:不是。我只是从 OP 中复制了示例,我不能打破我的好习惯 :) (嗨,顺便说一句)
  • 谢谢,我犯了一个愚蠢的错误——显然只有一张地图。不过,我不知道地图的每个元素都被称为一对。 KarrekSB:您提到在实际代码中部分使用 std::。我倾向于把所有的'using std::cin;'在开头键入行。这被认为是不好的做法吗?
【解决方案2】:

有点跑题了,但这里有一个使用 bimap 的性感解决方案,这是一个双方都作为键工作的地图。

#include <iostream>
#include <sstream>
#include <string>
#include <boost/bimap.hpp>
#include <boost/bimap/list_of.hpp>
#include <boost/bimap/set_of.hpp>

int main()
{
    boost::bimap<boost::bimaps::set_of<std::string>, boost::bimaps::list_of<int>> m;

    for (std::string line; std::getline(std::cin, line); )
    {
        ++m.left[line];
    }

    auto & bml = m.left;
    auto & bmr = m.right;

    bmr.sort();

    for (auto const & p : bml) { std::cout << p.first << " => " << p.second << "\n"; }
    for (auto const & p : bmr) { std::cout << p.first << " => " << p.second << "\n"; }
}

【讨论】:

    【解决方案3】:

    您想将地图的元素放入向量中。地图是成对的,而不是其他地图。因此,您的向量应该是成对的向量。

    也就是说,看起来您首先需要向量的原因是按地图中的值排序。那为什么不把你的地图改成map&lt; int, string &gt;呢?这将导致它按整数升序排序:地图中的元素按照特定的严格弱排序标准从低到高的键值排序。

    【讨论】:

      【解决方案4】:

      取消引用std::map&lt;std::string, int&gt;::const_iterator 会得到std::pair&lt;std:string, int&gt;,而不是std::map&lt;std::string, int&gt;,所以不要这样:

      vector<map<string, int> > vec_counters;
      

      你想要这个:

      vector<std::pair<string, int> > vec_counters;
      

      【讨论】:

      • 这个问题可能是有史以来最晦涩难懂的 C++ STL 使用问题之一。跟进 OP 的问题,std::pair 是否仍然让您受益于std::map 的快速检索?
      • @XavierHo:std::pair&lt;std::string, int&gt; 有一个std::string 和一个int,因此它实际上比std::map 快得多,std::map 具有潜在的多个元素的所有开销。
      • 在重新阅读OP的问题后,我想我误解了他的意图。是的,std::pair 将是用例的最佳选择。我在想实际上在std::vector 中有一个std::map,这是一个完全不同的数据结构。
      【解决方案5】:

      如果您想在插入地图条目后对矢量进行排序,那么您也可以使用 std::set 代替。集合中的元素总是排序的。如果您想稍后插入新元素,这将特别有用。但是,当您想按值对映射条目进行排序时,您必须将翻转的键值对存储到集合中。为了清楚起见,我省略了阅读以下 C++11 代码中的输入:

      int main() {
          std::map<std::string, int> counters{
              {"sorted", 2}, {"value" , 5}, {"is" , 2}, {"by" , 3}, {"this" , 1}
          };
      
          std::set<std::pair<int, std::string>> s;  // Use a set instead of a vector.
      
          for (auto const &kv : counters)
              s.emplace(kv.second, kv.first);  // Flip the pairs.
      
          for (auto const &vk : s)
              std::cout << vk.second << ": " << vk.first << std::endl;
      
          return 0;
      }
      

      输出:

      这个:1
      是:2
      排序:2
      作者:3
      值:5

      如果要按降序排序,可以按如下方式定义集合:

      using flippedPair = std::pair<int, std::string>;
      std::set<flippedPair, std::greater<flippedPair>> s;
      

      Shorter C++17 code on Coliru

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-27
        • 1970-01-01
        • 1970-01-01
        • 2017-01-08
        • 1970-01-01
        • 2021-12-31
        相关资源
        最近更新 更多