【问题标题】:How can I traverse/iterate an STL map?如何遍历/迭代 STL 映射?
【发布时间】:2011-05-11 13:51:12
【问题描述】:

我想遍历一个 STL 映射。我不想使用它的密钥。我不关心排序,我只是寻找一种访问它包含的所有元素的方法。我该怎么做?

【问题讨论】:

标签: c++ dictionary stl traversal stdmap


【解决方案1】:

是的,您可以遍历标准库map。这是用于遍历map 的基本方法,可作为遍历任何标准库集合的指南:

C++03/C++11:

#include <cstdlib>
#include <map>
#include <string>
using namespace std;

int main()
{
    typedef map<int,string> MyMap;
    MyMap my_map;
    // ... magic

    for( MyMap::const_iterator it = my_map.begin(); it != my_map.end(); ++it )
    {
      int key = it->first;
      string value = it->second;
    }
}

如果需要修改元素:

  • 使用iterator 而不是const_iterator
  • 与其从迭代器中复制值,不如获取一个引用并通过它修改值。

    for(MyMap::iterator it = my_map.begin(); it != my_map.end(); ++it) { int key = it->first; 字符串&值=它->秒; 如果(价值==“富”) 价值=“酒吧”; }

这就是您通常手动遍历标准库容器的方式。最大的区别在于,对于 map*it 的类型是 pair,而不是元素本身

C++11

如果您受益于 C++11 编译器(例如,带有 --std=c++11 或 MSVC 的最新 GCC),那么您还有其他选择。

首先,您可以使用 auto 关键字来摆脱所有令人讨厌的冗长:

#include <cstdlib>
#include <map>
#include <string>
using namespace std;

int main()
{
    map<int,string> my_map;
    // ... magic

    for( auto it = my_map.begin(); it != my_map.end(); ++it )
    {
      int key = it->first;
      string& value = it->second;
    }
}

其次,您还可以使用 lambda。结合decltype,这可能会导致代码更简洁(尽管需要权衡):

#include <cstdlib>
#include <map>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    map<int,string> my_map;
    // ... magic

    for_each(my_map.begin(), my_map.end(), [](decltype(*my_map.begin()) val)
    {
        string& value = val.second;
        int key = val.first;
    });
}

C++11 还引入了基于范围的for 循环的概念,您可能会认为它与其他语言相似。然而,一些编译器还不完全支持这一点——尤其是 MSVC。

#include <cstdlib>
#include <map>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    map<int,string> my_map;
    // ... magic

    for(auto val : my_map )
    {
        string& value = val.second;
        int key = val.first;
    }
}

【讨论】:

  • 在最新版本的 C++ 标准中,您可以将冗长的迭代器减速替换为 auto 关键字。
  • @RA:或者更好的是,基于范围的 for 循环。 g++ 4.6.0 已经支持这个。
  • @RA:严格来说,在最新的proposal下一个版本的C++标准中,你可以做你说的那件事。
  • @John:我很确定只要查看基于范围的 for 循环的定义,auto 就可以了。我对auto &amp; 的怀疑是auto 做了一个相当于模板参数推导的有点繁琐的事情,所以我可能错过了一些东西。我也没有足够好的编译器来测试。
  • 你不断地从迭代器中复制值。您应该使用引用,因为这允许操作地图中的数据。 string&amp; value = val.second; 我认为任何(普通)用户操纵该值都会期望地图的内部表示发生变化。
【解决方案2】:

与任何 STL 容器一样,begin()end() 方法返回可用于迭代地图的迭代器。取消引用映射迭代器会产生 std::pair&lt;const Key, Value&gt;

【讨论】:

  • 这是错误的,并不是所有的 STL 容器迭代器都会产生 std::pair。例如,向量或列表中不需要一对。
  • @EddieV223 很公平,我澄清了我的答案。
【解决方案3】:

C++17

由于C++17,您可以将range-based for loopsstructured bindings 一起用于遍历地图。结果代码,例如用于打印地图的所有元素,简短易读:

std::map<int, std::string> m{ {3, "a"}, {5, "b"}, {9, "c"} };

for (const auto &[k, v] : m)
    std::cout << "m[" << k << "] = " << v << std::endl;

输出:

m[3] = a
m[5] = b
m[9] = c

Code on Coliru

【讨论】:

    【解决方案4】:

    您可以像任何其他 STL 容器一样遍历 STL map:使用迭代器,例如

    for (std::map<key, value>::const_iterator
         i = myMap.begin(), end = myMap.end(); i != end; ++i)
    {
        // *i is a key-value pair
    }
    

    【讨论】:

    • 我想知道:一般来说,编译器会自动将myMap.end() 提升到循环之外吗?提升不变量是一种常见的优化,但我想知道它是否会被检测到,我想它可以通过内联的实现,但我不知道。想法?
    • @Matthieu:主要思想是myMap.end() 几乎可以肯定是一个微不足道的操作。几乎不值得一提,特别是考虑到迭代地图不是一个对缓存非常友好的操作。
    • @Matthieu:经过一些标头潜水:在 GNU 实现中,迭代器持有指向节点的指针,并且映射的“结束节点”嵌入在对象中。所以我认为假设可以内联几层调用,构造和返回一个结束迭代器基本上是一个指针副本,如果你幸运的话i != myMap.end()可能只是存储在i中的地址与@的比较987654327@。不过,我还没有反汇编任何代码来检查。
    【解决方案5】:

    forauto 一起用于C++11 及更高版本

    map<int,int> map_variable; //you can use any data type for keys, as well as value
    
    for(auto &x:map_variable)
    { 
        cout<<x.first ;// gives the key
        cout<<x.second; //gives the value
    }
    

    在 C++11 中引入了使用 autofor 的新格式

    赋予它像 python 等高级语言一样的功能

    已经有此类迭代的实现

    附: : map 变量保持值排序,因此在迭代时您将按排序顺序获取键

    【讨论】:

      【解决方案6】:

      您可以使用自动迭代器来迭代地图。

      代码片段:

      #include<bits/stdc++.h>
      using namespace std;
      
      int main()
      {
            ios::sync_with_stdio(false);
            map<string, int> mp;
      
            mp["a"]=500;
            mp["b"]=200;
            mp["d"]=300;
            mp["c"]=400;
      
            for(auto it=mp.begin(); it != mp.end(); it++)
            {
               cout<<it->first <<" : "<<it->second<<endl;
            }
            return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2011-05-29
        • 1970-01-01
        • 2011-04-02
        • 1970-01-01
        • 1970-01-01
        • 2011-05-01
        • 2015-06-05
        • 1970-01-01
        • 2011-02-28
        相关资源
        最近更新 更多