كيفية استرداد جميع المفاتيح (أو القيم) من خريطة std::map ووضعها في ناقل؟

StackOverflow https://stackoverflow.com/questions/110157

  •  02-07-2019
  •  | 
  •  

سؤال

هذه إحدى الطرق الممكنة للخروج:

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"));

بالطبع، يمكننا أيضًا استرداد جميع القيم من الخريطة عن طريق تحديد عامل آخر استرداد القيم.

هل هناك طريقة أخرى لتحقيق ذلك بسهولة؟(أتساءل دائمًا لماذا لا تتضمن std::map وظيفة عضو حتى نتمكن من القيام بذلك.)

هل كانت مفيدة؟

المحلول

على الرغم من أن الحل الخاص بك يجب أن يعمل، إلا أنه قد يكون من الصعب قراءته اعتمادًا على مستوى مهارات زملائك المبرمجين.بالإضافة إلى ذلك، فإنه ينقل الوظائف بعيدًا عن موقع الاتصال.مما قد يجعل الصيانة أكثر صعوبة قليلاً.

لست متأكدًا مما إذا كان هدفك هو إدخال المفاتيح في ناقل أو طباعتها لإخراجها، لذلك أقوم بالأمرين معًا.يمكنك تجربة شيء مثل هذا:

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";
}

أو حتى أبسط، إذا كنت تستخدم 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";
}

أنا شخصياً أحب إصدار BOOST_FOREACH لأنه يحتوي على عدد أقل من الكتابة وهو واضح جدًا بشأن ما يفعله.

نصائح أخرى

//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);

هناك محول نطاق التعزيز لهذا الغرض:

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

يوجد محول نطاق Map_values ​​مشابه لاستخراج القيم.

لقد أعطتنا لغة 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;});

إجابة @ 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;
}); 

وباستخدام C++ 14 (كما لاحظ @ivan.ukr) يمكننا استبداله decltype(map_in)::value_type مع auto.

لدى SGI STL امتداد يسمى select1st.من المؤسف أنها ليست في STL القياسية!

أعتقد أن 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") );

أنا شخصياً لا أعتقد أن هذا الأسلوب نظيف مثل أسلوب BOOST_FOREACH في هذه الحالة، لكن Boost::lambda يمكن أن يكون نظيفًا حقًا في حالات أخرى.

الحل الخاص بك جيد ولكن يمكنك استخدام مكرر للقيام بذلك:

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
}

أيضًا، إذا كان لديك Boost، فاستخدم Transform_iterator لتجنب عمل نسخة مؤقتة من المفاتيح.

يمكنك استخدام التعزيز متعدد الاستخدامات::transform_iterator.يسمح لك Transform_iterator بتحويل القيم المتكررة، على سبيل المثال في حالتنا عندما تريد التعامل مع المفاتيح فقط، وليس القيم.يرى http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/transform_iterator.html#example

جزء من 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;
}

أفضل حل STL غير sgi وغير معزز هو توسيع الخريطة :: المكرر مثل هذا:

template<class map_type>
class key_iterator : public map_type::iterator
{
public:
    typedef typename map_type::iterator map_iterator;
    typedef typename map_iterator::value_type::first_type key_type;

    key_iterator(const map_iterator& other) : map_type::iterator(other) {} ;

    key_type& operator *()
    {
        return map_type::iterator::operator*().first;
    }
};

// helpers to create iterators easier:
template<class map_type>
key_iterator<map_type> key_begin(map_type& m)
{
    return key_iterator<map_type>(m.begin());
}
template<class map_type>
key_iterator<map_type> key_end(map_type& m)
{
    return key_iterator<map_type>(m.end());
}

ثم استخدمها هكذا:

        map<string,int> test;
        test["one"] = 1;
        test["two"] = 2;

        vector<string> keys;

//      // method one
//      key_iterator<map<string,int> > kb(test.begin());
//      key_iterator<map<string,int> > ke(test.end());
//      keys.insert(keys.begin(), kb, ke);

//      // method two
//      keys.insert(keys.begin(),
//           key_iterator<map<string,int> >(test.begin()),
//           key_iterator<map<string,int> >(test.end()));

        // method three (with helpers)
        keys.insert(keys.begin(), key_begin(test), key_end(test));

        string one = keys[0];

فيما يلي قالب دالة رائع يستخدم 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;
}

تحقق من ذلك هنا: http://ideone.com/lYBzpL

مشابه قليلاً لأحد الأمثلة هنا، مبسط من std::map منظور الاستخدام.

template<class KEY, class VALUE>
std::vector<KEY> getKeys(const std::map<KEY, VALUE>& map)
{
    std::vector<KEY> keys(map.size());
    for (const auto& it : map)
        keys.push_back(it.first);
    return keys;
}

استخدم مثل هذا:

auto keys = getKeys(yourMap);

استنادًا إلى حل @rusty-parks، ولكن في الإصدار c++ 17:

std::map<uint32_t, uint32_t> items;
std::vector<uint32_t> itemKeys;
for (auto const& [key, std:ignore] : items) {
  itemKeys.emplace_back(key);
}

(أتساءل دائمًا لماذا لا تتضمن std::map وظيفة عضو حتى نتمكن من القيام بذلك.)

لأنه لا يمكنه القيام بذلك بشكل أفضل مما يمكنك القيام به.إذا كان تنفيذ الطريقة لن يكون أفضل من تنفيذ وظيفة حرة، فيجب عليك بشكل عام ألا تكتب طريقة؛يجب عليك كتابة وظيفة مجانية.

كما أنه ليس من الواضح على الفور سبب فائدته على أي حال.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top