如何从std :: map中检索所有键(或值)并将它们放入向量中?

Owe*_*wen 222 c++ dictionary stl stdmap

这是我出来的可能方式之一:

struct RetrieveKey
{
    template <typename T>
    typename T::first_type operator()(T keyValuePair) const
    {
        return keyValuePair.first;
    }
};

map<int, int> m;
vector<int> keys;

// Retrieve all keys
transform(m.begin(), m.end(), back_inserter(keys), RetrieveKey());

// Dump all keys
copy(keys.begin(), keys.end(), ostream_iterator<int>(cout, "\n"));
Run Code Online (Sandbox Code Playgroud)

当然,我们也可以通过定义另一个仿函数RetrieveValues从地图中检索所有值.

有没有其他方法可以轻松实现这一目标?(我总是想知道为什么std :: map不包含我们这样做的成员函数.)

Jer*_*nes 162

虽然您的解决方案应该可行,但根据您的程序员的技能水平,可能难以阅读.此外,它还将功能从呼叫站点移开.这可能会使维护变得更加困难.

我不确定你的目标是将密钥放入矢量中还是将它们打印到cout所以我正在做两件事.你可以尝试这样的事情:

map<int, int> m;
vector<int> v;
for(map<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
  v.push_back(it->first);
  cout << it->first << "\n";
}
Run Code Online (Sandbox Code Playgroud)

或者甚至更简单,如果你使用Boost:

map<int,int> m;
pair<int,int> me; // what a map<int, int> is made of
vector<int> v;
BOOST_FOREACH(me, m) {
  v.push_back(me.first);
  cout << me.first << "\n";
}
Run Code Online (Sandbox Code Playgroud)

就个人而言,我喜欢BOOST_FOREACH版本,因为键入的内容较少,而且它的内容非常明确.

  • 好奇,预先设定矢量以防止调整大小分配是不是有意义? (17认同)
  • @Jere - 你真的和`BOOST_FOREACH`合作过吗?你在这里提出的代码是完全错误的 (4认同)
  • @Jamie - 这是另一种方式,但是如果类型包含逗号,则boost文档显示在BOOST_FOREACH之前指定变量及其类型.他们还显示了typedefing它.所以,我很困惑,我的代码出了什么问题? (2认同)
  • 不要忘记执行`v.reserve(m.size())`以避免在传输过程中调整矢量大小. (2认同)

小智 141

//c++0x too
std::map<int,int> mapints;
std::vector<int> vints;
vints.reserve(mapints.size());
for(auto const& imap: mapints)
    vints.push_back(imap.first);
Run Code Online (Sandbox Code Playgroud)

  • @BenHymers但它现在对任何读这个问题的人都有用,这就是SO的全部意义 - 不仅帮助提问者,还帮助其他所有人. (33认同)
  • for(auto&imap)更精确,因为没有复制操作. (8认同)
  • 尼斯.忘记`it = ... begin(); 它!= ...结束.最好的当然是std :: map有一个方法keys()返回该向量... (3认同)
  • @BenHymers:在我看来,这个答案是在12月12日22:33回答的,这是几个月后_C++ 11变成了C++. (2认同)
  • @StudentT,更好的是,`for(auto const&imap:mapints)`. (2认同)
  • 我更喜欢`for(auto && imap:mapints)`.见http://edmundv.home.xs4all.nl/blog/2014/01/28/use-auto-and-and-for-range-based-for-loops/ (2认同)
  • 此外,我们中的一些人必须在没有C++ 11支持的环境中工作-_- (2认同)
  • 如果您打算有效地使用它,则应该在循环之前添加 `vints.reserve( mapints.size() );`。 (2认同)
  • 来自未来的人在这里。关于@user283145 的评论,现在是 C++==C++17 并且不会持续太久。一方面,我很欣赏答案指定语言兼容性。“C++”是一种已经并将继续改变的语言。 (2认同)

Mer*_*ime 80

使用 C++20 的另一种方法

范围库有一个键视图,它检索类似对/元组类型中的第一个元素:

#include <ranges>

auto kv = std::views::keys(m);
std::vector<int> keys{ kv.begin(), kv.end() };
Run Code Online (Sandbox Code Playgroud)

值得一提的两个相关观点:

  1. 值 - 获取映射中的值(对/元组类型中的第二个元素)
  2. elements - 获取类似元组类型的第 n 个元素

  • 这是现在最好的解决方案 (5认同)
  • 这是非常容易实现的。C++已经取得了长足的进步! (3认同)

Ala*_*air 59

为此目的有一个增压范围适配器:

vector<int> keys;
// Retrieve all keys
boost::copy(m | boost::adaptors::map_keys, std::back_inserter(keys));
Run Code Online (Sandbox Code Playgroud)

有一个类似的map_values范围适配器用于提取值.

  • 这真遗憾.Boost 1.42于2010年2月发布,距离Squeeze超过2.5年. (2认同)

Dan*_*Dan 43

C++ 0x为我们提供了更好的解决方案:

std::vector<int> keys;

std::transform(
    m_Inputs.begin(),
    m_Inputs.end(),
    std::back_inserter(keys),
    [](const std::map<int,int>::value_type &pair){return pair.first;});
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,没有什么优秀的.std :: vector <int>键; keys.reserve(m_Inputs.size()); for(auto keyValue:m_Inputs){keys.push_back(keyValue.first); 比神秘的变换要好得多.即使在性能方面.这个更好. (20认同)
  • 只想添加 - 可以使用[](const auto&pair) (4认同)
  • 如果您想要相同的性能,也可以在此处保留按键的大小.如果要避免for循环,请使用转换. (3认同)
  • lambda中的@ ivan.ukr自动参数是c ++ 14 (3认同)

Mad*_*yar 21

基于@rusty-parks 解决方案,但在 c++17 中:

std::map<int, int> items;
std::vector<int> itemKeys;

for (const auto& [key, _] : items) {
    itemKeys.push_back(key);
}
Run Code Online (Sandbox Code Playgroud)

  • @jb 谢谢。事实上,“std::ignore”旨在与“std::tie”一起使用,但不能与结构绑定一起使用。我已经更新了我的代码。 (2认同)

Jam*_*orn 12

@ DanDan的回答,使用C++ 11是:

using namespace std;
vector<int> keys;

transform(begin(map_in), end(map_in), back_inserter(keys), 
            [](decltype(map_in)::value_type const& pair) {
    return pair.first;
}); 
Run Code Online (Sandbox Code Playgroud)

并使用C++ 14(如@ ivan.ukr所述)我们可以替换decltype(map_in)::value_typeauto.

  • 您可以添加`keys.reserve(map_in.size());`以提高效率. (3认同)

Chr*_*ung 10

SGI STL有一个名为的扩展名select1st.太糟糕了,它不是标准的STL!


Кон*_*Ван 10

使用C++17 的结构化绑定(\xe2\x80\x9cdestructuring\xe2\x80\x9d) 声明语法,

\n

你可以这样做,这样更容易理解。

\n
// To get the keys\nstd::map<int, double> map;\nstd::vector<int> keys;\nkeys.reserve(map.size());\nfor(const auto& [key, value] : map) {\n    keys.push_back(key);\n}\n
Run Code Online (Sandbox Code Playgroud)\n
// To get the values\nstd::map<int, double> map;\nstd::vector<double> values;\nvalues.reserve(map.size());\nfor(const auto& [key, value] : map) {\n    values.push_back(value);\n}\n
Run Code Online (Sandbox Code Playgroud)\n


pax*_*977 9

我认为上面提到的BOOST_FOREACH很好很干净,但是,还有另一个使用BOOST的选项.

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

std::map<int, int> m;
std::vector<int> keys;

using namespace boost::lambda;

transform(      m.begin(), 
                m.end(), 
                back_inserter(keys), 
                bind( &std::map<int,int>::value_type::first, _1 ) 
          );

copy( keys.begin(), keys.end(), std::ostream_iterator<int>(std::cout, "\n") );
Run Code Online (Sandbox Code Playgroud)

就个人而言,我不认为这种方法在这种情况下与BOOST_FOREACH方法一样干净,但在其他情况下,boost :: lambda可能非常干净.


Bri*_*ndy 8

您的解决方案很好,但您可以使用迭代器来执行此操作:

std::map<int, int> m;
m.insert(std::pair<int, int>(3, 4));
m.insert(std::pair<int, int>(5, 6));
for(std::map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
{
    int key = it->first;
    int value = it->second;
    //Do something
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*tos 7

此外,如果您有Boost,请使用transform_iterator以避免生成密钥的临时副本.


小智 7

C ++ 11的特点:

std::map<uint32_t, uint32_t> items;
std::vector<uint32_t> itemKeys;
for (auto & kvp : items)
{
    itemKeys.emplace_back(kvp.first);
    std::cout << kvp.first << std::endl;
}
Run Code Online (Sandbox Code Playgroud)


Olp*_*pah 7

在 C++20 中使用范围,您可以像这样使用 std::ranges::copy

#include <ranges>
std::map<int,int> mapints;
std::vector<int> vints;

std::ranges::copy(mapints | std::views::keys, std::back_inserter(vints));
Run Code Online (Sandbox Code Playgroud)

如果你想要值而不是键

std::ranges::copy(mapints | std::views::values, std::back_inserter(vints));
Run Code Online (Sandbox Code Playgroud)

如果你不喜欢管道语法

std::ranges::copy(std::views::values(mapints), std::back_inserter(vints));
Run Code Online (Sandbox Code Playgroud)


ami*_*mit 5

您可以使用通用的boost :: transform_iterator。transform_iterator允许您转换迭代的值,例如在我们的情况下,当您只想处理键而不是值时。参见http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/transform_iterator.html#example


Cle*_*aff 5

这是一个使用C ++ 11魔术的不错的函数模板,可同时用于std :: map和std :: unordered_map:

template<template <typename...> class MAP, class KEY, class VALUE>
std::vector<KEY>
keys(const MAP<KEY, VALUE>& map)
{
    std::vector<KEY> result;
    result.reserve(map.size());
    for(const auto& it : map){
        result.emplace_back(it.first);
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

在这里查看:http : //ideone.com/lYBzpL