从 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&lt;std::pair&lt;const Key, Val&gt;&gt; v(map.begin(), map.end()); ,它应该给你一个键值对向量。 @keith.layne:我正在为键和值寻找单独的向量。 正如我所说,没有任何内置功能。见下文。 @muntoo:不确定编辑的内容。 vector&lt;string&gt; 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 mapset 容器。

【讨论】:

好的,所以我想没有什么比迭代地图更好的了。我不认识您使用的语法。 (auto kv : map) 表示什么。我本来希望只对地图元素进行一次迭代(即 for 循环)。 @FaheemMitha 这是新的 C++11 for 循环。它完全按照它的样子做,并结合auto 使事情变得更整洁。 auto 使您不必显式编写 kv 的类型。有几种方法可以完成基本相同的事情,包括迭代器上的 for 循环、带有 lambda 的for_each 等。既然你提到了unordered_map,我假设你使用的是 C++11。 使用储备可以提高效率,但没有比这更快或更容易的了。 我会在这里使用auto&amp; 而不是auto 以避免不必要的复制对(以及底层的第一/第二成员,如果它们是结构)。它不适用于set 容器,因为它们的value_type 不是std::pair&lt;K, V&gt;,而是Key/Val 类型本身。 你可以写成std::vector&lt;Key&gt; keys(map.size());而不是std::vector&lt;Key&gt; 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

测试它按预期打印键和值。

【讨论】:

你能解释一下吗 能不能写一个独立的可以编译的例子?此外,如果您可以提及要使用的编译器并提供用于编译它的命令行,那将很有帮助。谢谢。 另外,这里的KeyValueum 是什么?你还没有定义它们。也许您正在使用问题中的定义,即“unordered_map um;”,但在这种情况下,您应该在这里再次提及,无论如何。 适用于 clang 3.5 和 gcc 4.9。与普通循环相比,这有什么效率优势吗? lambas 不应该引入任何开销,它们(像任何其他仿函数一样)可以内联到 transform 循环中。但是当使用auto 时,一定要记住它会推导出值类型,所以那些基于范围的 for 循环会引入一些副本。您可以使用const auto&amp; 而不是普通的auto,这很有意义。【参考方案3】:

在 STL 中,没有内置方法可以从映射中获取所有键或值。

迭代无序映射或常规映射没有什么不同,最好的方法是对其进行迭代并将键或值收集到向量。

您可以编写一个模板函数来迭代任何类型的地图。

【讨论】:

【参考方案4】:

加入晚了,但认为这可能对某人有所帮助。 使用key_typemapped_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 获取键和值列表的主要内容,如果未能解决你的问题,请参考以下文章

获取以索引为导向的嵌套字典中的键和值列表

如何在 C# 中的键和值列表上使用 Lambda 函数获取最大值和最小值?

如何从 NSDictionary 中获取键和值?

如何从 Pyspark 中的 MapType 列获取键和值

如何将 java 映射展平为列表,以便列表交替键和值?

使用 min 从字典中获取最低键和值 [重复]