【问题标题】:Obtaining list of keys and values from unordered_map从 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 建议的那样,同时执行这两种操作会更快

标签: c++ vector c++11 std unordered-map


【解决方案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);  
      } 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-03-15
        • 1970-01-01
        • 1970-01-01
        • 2017-10-23
        • 1970-01-01
        • 2021-01-22
        相关资源
        最近更新 更多