【发布时间】:2011-05-11 13:51:12
【问题描述】:
我想遍历一个 STL 映射。我不想使用它的密钥。我不关心排序,我只是寻找一种访问它包含的所有元素的方法。我该怎么做?
【问题讨论】:
标签: c++ dictionary stl traversal stdmap
我想遍历一个 STL 映射。我不想使用它的密钥。我不关心排序,我只是寻找一种访问它包含的所有元素的方法。我该怎么做?
【问题讨论】:
标签: c++ dictionary stl traversal stdmap
是的,您可以遍历标准库map。这是用于遍历map 的基本方法,可作为遍历任何标准库集合的指南:
#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 编译器(例如,带有 --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;
}
}
【讨论】:
auto 就可以了。我对auto & 的怀疑是auto 做了一个相当于模板参数推导的有点繁琐的事情,所以我可能错过了一些东西。我也没有足够好的编译器来测试。
string& value = val.second; 我认为任何(普通)用户操纵该值都会期望地图的内部表示发生变化。
与任何 STL 容器一样,begin() 和 end() 方法返回可用于迭代地图的迭代器。取消引用映射迭代器会产生 std::pair<const Key, Value>。
【讨论】:
由于C++17,您可以将range-based for loops 与structured 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
【讨论】:
您可以像任何其他 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() 提升到循环之外吗?提升不变量是一种常见的优化,但我想知道它是否会被检测到,我想它可以通过内联的实现,但我不知道。想法?
myMap.end() 几乎可以肯定是一个微不足道的操作。几乎不值得一提,特别是考虑到迭代地图不是一个对缓存非常友好的操作。
i != myMap.end()可能只是存储在i中的地址与@的比较987654327@。不过,我还没有反汇编任何代码来检查。
将for 与auto 一起用于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 中引入了使用 auto 的 for 的新格式
赋予它像 python 等高级语言一样的功能
已经有此类迭代的实现
附: : map 变量保持值排序,因此在迭代时您将按排序顺序获取键
【讨论】:
您可以使用自动迭代器来迭代地图。
#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;
}
【讨论】: