从 unordered_map 获取键和值列表
Posted
技术标签:
【中文标题】从 unordered_map 获取键和值列表【英文标题】:Obtaining list of keys and values from unordered_map 【发布时间】:2012-01-19 00:25:31 【问题描述】:从unordered_map
获取键和值列表(作为vector
)的最有效方法是什么?
为了具体起见,假设有问题的地图是unordered_map<string, double>
。
然后我想以vector<string>
获取键,以vector<double>
获取值。
unordered_map<string, double> um;
vector<string> vs = um.enum_keys();
vector<double> vd = um.enum_values();
我可以遍历地图并收集结果,但还有更多 有效的方法?有一个也适用于常规地图的方法会很好, 因为我可能会切换到那个。
【问题讨论】:
查看标准草案,我看不到获得您想要的东西的简单方法,但我可能会遗漏一些东西。你可以说std::vector<std::pair<const Key, Val>> v(map.begin(), map.end());
,它应该给你一个键值对向量。
@keith.layne:我正在为键和值寻找单独的向量。
正如我所说,没有任何内置功能。见下文。
@muntoo:不确定编辑的内容。 vector<string> vs = um.enum_keys();
应该表示什么?
Boost 有一个转换迭代器,它可以只提取键或值,但正如 Keith 建议的那样,同时执行这两种操作会更快
【参考方案1】:
好的,给你:
std::vector<Key> keys;
keys.reserve(map.size());
std::vector<Val> vals;
vals.reserve(map.size());
for(auto kv : map)
keys.push_back(kv.first);
vals.push_back(kv.second);
效率可能会提高,但确实如此。不过,您在两个容器上进行操作,因此实际上没有任何 STL 魔法可以隐藏这一事实。
正如 Louis 所说,这适用于任何 STL map
或 set
容器。
【讨论】:
好的,所以我想没有什么比迭代地图更好的了。我不认识您使用的语法。(auto kv : map)
表示什么。我本来希望只对地图元素进行一次迭代(即 for 循环)。
@FaheemMitha 这是新的 C++11 for 循环。它完全按照它的样子做,并结合auto
使事情变得更整洁。 auto
使您不必显式编写 kv 的类型。有几种方法可以完成基本相同的事情,包括迭代器上的 for 循环、带有 lambda 的for_each
等。既然你提到了unordered_map
,我假设你使用的是 C++11。
使用储备可以提高效率,但没有比这更快或更容易的了。
我会在这里使用auto&
而不是auto
以避免不必要的复制对(以及底层的第一/第二成员,如果它们是结构)。它不适用于set
容器,因为它们的value_type
不是std::pair<K, V>
,而是Key/Val 类型本身。
你可以写成std::vector<Key> keys(map.size());
而不是std::vector<Key> keys(map.size());
,和其他向量一样【参考方案2】:
使用 C++-14,您还可以执行以下操作(已编辑以包含完整源代码):
#include <algorithm>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;
typedef string Key;
typedef int Value;
auto key_selector = [](auto pair)return pair.first;;
auto value_selector = [](auto pair)return pair.second;;
int main(int argc, char** argv)
// Create a test map
unordered_map<Key, Value> map;
map["Eight"] = 8;
map["Ten"] = 10;
map["Eleven"] = 11;
// Vectors to hold keys and values
vector<Key> keys(map.size());
vector<Value> values(map.size());
// This is the crucial bit: Transform map to list of keys (or values)
transform(map.begin(), map.end(), keys.begin(), key_selector);
transform(map.begin(), map.end(), values.begin(), value_selector);
// Make sure this worked: Print out vectors
for (Key key : keys) cout << "Key: " << key << endl;
for (Value value : values) cout << "Value: " << value << endl;
return 0;
我用以下命令编译了这个:
g++ keyval.cpp -std=c++14 -o keyval
测试它按预期打印键和值。
【讨论】:
你能解释一下吗 能不能写一个独立的可以编译的例子?此外,如果您可以提及要使用的编译器并提供用于编译它的命令行,那将很有帮助。谢谢。 另外,这里的Key
和Value
和um
是什么?你还没有定义它们。也许您正在使用问题中的定义,即“unordered_maptransform
循环中。但是当使用auto
时,一定要记住它会推导出值类型,所以那些基于范围的 for 循环会引入一些副本。您可以使用const auto&
而不是普通的auto
,这很有意义。【参考方案3】:
在 STL 中,没有内置方法可以从映射中获取所有键或值。
迭代无序映射或常规映射没有什么不同,最好的方法是对其进行迭代并将键或值收集到向量。
您可以编写一个模板函数来迭代任何类型的地图。
【讨论】:
【参考方案4】:加入晚了,但认为这可能对某人有所帮助。
使用key_type
和mapped_type
的两个模板函数。
namespace mapExt
template<typename myMap>
std::vector<typename myMap::key_type> Keys(const myMap& m)
std::vector<typename myMap::key_type> r;
r.reserve(m.size());
for (const auto&kvp : m)
r.push_back(kvp.first);
return r;
template<typename myMap>
std::vector<typename myMap::mapped_type> Values(const myMap& m)
std::vector<typename myMap::mapped_type> r;
r.reserve(m.size());
for (const auto&kvp : m)
r.push_back(kvp.second);
return r;
用法:
std::map<long, char> mO;
std::unordered_map<long, char> mU;
// set up the maps
std::vector<long> kO = mapExt::Keys(mO);
std::vector<long> kU = mapExt::Keys(mU);
std::vector<char> vO = mapExt::Values(mO);
std::vector<char> vU = mapExt::Values(mU);
【讨论】:
【参考方案5】:类似于@Keith Layne 的回答,但保留是在一行中完成的; 并且 for 循环使用引用(而不是按每个条目的值复制它)并将其设为 const。但是如果可以使用 C++14,那么@Marius Renn 的答案应该会更好。
std::map<long, char> mO;
// populate the mO
std::vector<long> keys(mO.size());
std::vector<char> vals(mO.size());
for(const auto &kv : mO)
keys.push_back(kv.first);
vals.push_back(kv.second);
【讨论】:
以上是关于从 unordered_map 获取键和值列表的主要内容,如果未能解决你的问题,请参考以下文章