Std :: मैप से सभी कुंजियों (या मानों) को कैसे प्राप्त करें और उन्हें वेक्टर में डालें?


246

यह उन संभावित तरीकों में से एक है जो मैं बाहर आता हूं:

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 :: मैप में हमारे लिए ऐसा करने के लिए कोई सदस्य फ़ंक्शन शामिल नहीं है।)


10
आपका समाधान सबसे अच्छा है ...
linello

4
केवल मुझे लगता है कि मैं इसे जोड़ूंगा keys.reserve(m.size());
गैलिक

जवाबों:


176

जबकि आपके समाधान को काम करना चाहिए, आपके साथी प्रोग्रामर के कौशल स्तर के आधार पर पढ़ना मुश्किल हो सकता है। इसके अतिरिक्त, यह कॉल साइट से कार्यक्षमता को दूर ले जाता है। जो रखरखाव को थोड़ा और कठिन बना सकता है।

मुझे यकीन नहीं है कि अगर आपका लक्ष्य एक सदिश में चाबियाँ प्राप्त करना है या उन्हें 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";
}

या इससे भी सरल, यदि आप बूस्ट का उपयोग कर रहे हैं:

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 संस्करण पसंद है क्योंकि इसमें टाइपिंग कम है और यह स्पष्ट है कि यह क्या कर रहा है।


1
मेरे Google खोज के बाद गो आंकड़े मैं वापस यहां समाप्त कर दूंगा। तुम्हारा जवाब है मुझे पसंद है :)
एमपीन

4
@ जेरे - क्या आपने वास्तव में साथ काम किया है BOOST_FOREACH? आपके द्वारा यहां प्रस्तावित कोड पूरी तरह से गलत है
मैनुअल

2
@ जैमी - यह एक और तरीका है, लेकिन बूस्ट डॉक्स को वेरिएबल और इसके प्रकार को BOOST_FOREACH से पहले निर्दिष्ट करता है यदि टाइप में कॉमा होता है। वे भी इसे टाइपिंग करते दिखाते हैं। तो, मैं उलझन में हूं, मेरे कोड में क्या गलत है?
Jere.Jones 16

17
जिज्ञासु, यह आवंटन को रोकने के लिए वेक्टर को निर्धारित करने के लिए समझ में नहीं आएगा?
एलन

2
v.reserve(m.size())स्थानांतरण के दौरान वेक्टर का आकार बदलने से बचने के लिए क्या करना न भूलें ।
ब्रायन व्हाइट

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

4
अच्छा लगा। के बारे में भूल जाओ it = ...begin(); it != ...end। निकेस्ट निश्चित रूप से एसटीडी होगा :: नक्शा एक विधि कुंजियाँ () है कि वेक्टर लौट रहा है ...
Masterxilo

2
@BenHymers: ऐसा लगता है कि यह जवाब C ++ 11 के C ++ बनने के answered Mar 13 '12 at 22:33कई महीने बाद दिया गया था ।
सेबेस्टियन मच

37
@BenHymers लेकिन अब सवाल पढ़ने वाले किसी व्यक्ति के लिए इसका उपयोग किया जाता है, जो कि SO है, जो केवल पूछने वाले की मदद कर रहा है, बल्कि हर किसी की नहीं।
ल्यूचियन ग्रिगोर

9
(ऑटो और इमैप) अधिक सटीक है क्योंकि कोई प्रतिलिपि कार्रवाई नहीं है।
नमस्ते वर्ल्ड

2
@StudentT, बेहतर अभी तक for(auto const & imap : mapints),।
cp.engr

61

इस उद्देश्य के लिए एक बूस्ट रेंज एडाप्टर है :

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

मान निकालने के लिए एक समान map_values ​​रेंज एडाप्टर है।


1
दुर्भाग्य से, ऐसा लगता boost::adaptorsहै कि बूस्ट 1.43 तक उपलब्ध नहीं है। डेबियन (निचोड़) की वर्तमान स्थिर रिलीज केवल बूस्ट 1.42 प्रदान करती है
मिकाल ले बैलिफ

2
वह अफसोस की बात है। बूस्ट 1.42 को स्क्वीज़ से 2.5 साल पहले, फ़रवरी 2010 में रिलीज़ किया गया था।
अलास्टेयर

इस बिंदु पर, स्क्वीज़ अपडेट और या बैकपो रेपो को बूस्ट 1.44 की पेशकश नहीं करनी चाहिए?
लुइस माचूका

किस हेडर को बढ़ावा दिया जाता है?
जेम्स विर्ज़बा

1
लिंक किए गए डोको को देखें, यह परिभाषित हैboost/range/adaptor/map.hpp
एलास्टेयर

46

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

22
मेरे विचार में इसके बारे में कुछ भी उत्कृष्ट नहीं है। std :: वेक्टर <int> कुंजियाँ; keys.reserve (m_Inputs.size ()); for (auto keyValue: m_Inputs) {keys.push_back (keyValue.first); } क्रिप्टो ट्रांसफॉर्मेशन से कहीं बेहतर है। यहां तक ​​कि प्रदर्शन के मामले में भी। यह बेहतर है।
जगन्नाथ

5
यदि आप तुलनीय प्रदर्शन चाहते हैं, तो आप यहां कुंजियों का आकार भी आरक्षित कर सकते हैं। यदि आप लूप से बचना चाहते हैं तो ट्रांसफॉर्मेशन का उपयोग करें।
दानादान

4
बस जोड़ना चाहते हैं - का उपयोग कर सकते हैं [] (
कास्ट

@ ivan.ukr क्या संकलक आप उपयोग कर रहे हैं? इस सिंटैक्स की यहाँ अनुमति नहीं है: 'const auto &': एक पैरामीटर में एक प्रकार नहीं हो सकता है जिसमें 'auto' शामिल हो
Gobe

4
@ ivan.ukr लाम्बदा में ऑटो पैरामीटर c ++ 14
roalz

16

@ दान का जवाब, 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;
}); 

और सी का उपयोग कर ++ 14 (के रूप में @ ivan.ukr द्वारा नोट) हम जगह ले सकता है decltype(map_in)::value_typeके साथ auto


5
आप keys.reserve(map_in.size());दक्षता के लिए जोड़ सकते हैं ।
गैलिक

मुझे लगता है कि रूपांतरण विधि वास्तव में लूप की तुलना में अधिक कोड लेती है।
user1633272

const को टाइप के पीछे रखा जा सकता है! मैं लगभग भूल गया हूँ।
जांग


10

आपका समाधान ठीक है लेकिन आप इसे करने के लिए एक पुनरावृत्ति का उपयोग कर सकते हैं:

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
}

10

@ जंग-पार्कों के समाधान के आधार पर, लेकिन c ++ 17 में:

std :: map <int, int> आइटम;
std :: वेक्टर <int> itemKeys;

(कास्ट ऑटो और [कुंजी, अनदेखा]: आइटम)
{
    itemKeys.push_back (कुंजी);
}

मुझे नहीं लगता कि std::ignoreइस तरह से संरचित बाइंडिंग में सीए का उपयोग किया जा सकता है। मुझे एक संकलन त्रुटि हो रही है। यह केवल एक नियमित चर का उपयोग करने के लिए पर्याप्त होना चाहिए जैसे ignoredकि बस इसका उपयोग नहीं किया जाता है।
jb

1
@ जेबी धन्यवाद। दरअसल, संरचनात्मक बाइंडिंग के साथ std::ignoreउपयोग करने के लिए अभिप्रेत है std::tie। मैंने अपना कोड अपडेट कर दिया है।
मडियार

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

व्यक्तिगत रूप से, मुझे नहीं लगता कि यह दृष्टिकोण इस मामले में BOOST_FOREACH दृष्टिकोण जितना ही साफ है, लेकिन बढ़ावा देने वाला :: लंबोदर अन्य मामलों में वास्तव में साफ हो सकता है।


7

इसके अलावा, यदि आपके पास बूस्ट है, तो चाबियों की एक अस्थायी प्रतिलिपि बनाने से बचने के लिए ट्रांसफॉर्मेटर का उपयोग करें।


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

5

आप बहुमुखी बढ़ावा का उपयोग कर सकते हैं :: transform_iterator। ट्रांसफॉर्म_टरेटर आपको पुनरावृत्त मूल्यों को बदलने की अनुमति देता है, उदाहरण के लिए हमारे मामले में जब आप केवल कुंजियों से निपटना चाहते हैं, न कि मूल्यों के साथ। Http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/transform_iterator.html#example देखें


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

इसे यहां देखें : http://ideone.com/lYBzpL


4

सबसे अच्छा गैर-एसजीआई, गैर-बूस्ट एसटीएल समाधान मानचित्र का विस्तार करने के लिए है :: itter जैसे:

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];

1
मैं इसे पाठक के लिए छोड़ दूंगा कि यदि आवश्यक हो, तो कॉन्स्टिटर_टेटर भी बना सकता है और पुनरावृत्तियों को उल्टा कर सकता है।
मारीस

-1

परमाणु मानचित्र उदाहरण के साथ

#include <iostream>
#include <map>
#include <vector> 
#include <atomic>

using namespace std;

typedef std::atomic<std::uint32_t> atomic_uint32_t;
typedef std::map<int, atomic_uint32_t> atomic_map_t;

int main()
{
    atomic_map_t m;

    m[4] = 456;
    m[2] = 45678;

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

    return 0;
}

-2

यहां एक उदाहरण के समान थोड़ा, 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);

2
अरे, मुझे पता है कि यह उत्तर पुराना है लेकिन यह भी गलत है। आकार के साथ प्रारंभिक का map.size()मतलब है कि वेक्टर आकार का दोगुना रिटर्न। कृपया किसी और को सिरदर्द से बचाने के लिए ठीक करें :(
thc

-3

(मैं हमेशा सोच रहा हूं कि std :: मैप में हमारे लिए ऐसा करने के लिए कोई सदस्य फ़ंक्शन शामिल नहीं है।)

क्योंकि आप इसे किसी भी बेहतर तरीके से नहीं कर सकते हैं। यदि एक विधि का कार्यान्वयन एक नि: शुल्क फ़ंक्शन के कार्यान्वयन से बेहतर नहीं होगा, तो सामान्य तौर पर आपको एक विधि नहीं लिखनी चाहिए; आपको एक मुफ्त फ़ंक्शन लिखना चाहिए।

यह भी तुरंत स्पष्ट नहीं है कि यह वैसे भी क्यों उपयोगी है।


8
किसी लाइब्रेरी को एक विधि प्रदान करने के लिए दक्षता के अलावा अन्य कारण हैं, जैसे "बैटरी शामिल" कार्यक्षमता, और एक सुसंगत, संलग्न एपीआई। हालांकि माना जाता है कि इनमें से कोई भी शब्द STL का विशेष रूप से अच्छा वर्णन नहीं करता है :) Re। स्पष्ट नहीं है कि यह उपयोगी क्यों है - वास्तव में? मुझे लगता है कि यह बहुत स्पष्ट है कि उपलब्ध कुंजियों को सूचीबद्ध करना मानचित्र / तानाशाही के साथ करने में सक्षम होने के लिए एक उपयोगी चीज है: यह इस बात पर निर्भर करता है कि आप इसके लिए क्या उपयोग कर रहे हैं।
andybuckley

4
इस तर्क से, हमें ऐसा नहीं करना चाहिए empty()क्योंकि इसे लागू किया जा सकता है size() == 0
जीडी

1
@ Gd1 ने क्या कहा। जबकि एक वर्ग में बहुत अधिक कार्यात्मक अतिरेक नहीं होना चाहिए, बिल्कुल शून्य पर जोर देना एक अच्छा विचार आईएमओ नहीं है - कम से कम जब तक सी ++ हमें तरीकों में मुफ्त कार्यों को "आशीर्वाद" देने की अनुमति नहीं देता है।
einpoklum

1
C ++ के पुराने संस्करणों में ऐसे कंटेनर थे जिनके लिए खाली () और आकार () में यथोचित अलग-अलग प्रदर्शन की गारंटी हो सकती है, और मुझे लगता है कि यह अनुमति देने के लिए कल्पना पर्याप्त रूप से ढीली थी (विशेषकर, लिंक की गई सूचियाँ जो निरंतर-समय विभाजन की पेशकश करती थीं) () । जैसे, उन्हें समझने से समझ में आ गया। मुझे नहीं लगता कि इस विसंगति की अनुमति किसी भी अधिक है, हालांकि।
DrPizza

मैं सहमत हूँ। C ++ std::map<T,U>जोड़े के कंटेनर के रूप में व्यवहार करता है । पाइथन में, dictजब इसकी अधिकता होती है, तो इसकी कुंजियों की तरह कार्य करता है, लेकिन आपको d.items()C ++ व्यवहार प्राप्त करने के लिए कहता है। अजगर भी प्रदान करता है d.values()std::map<T,U>निश्चित रूप से एक keys()और values()विधि प्रदान कर सकता है जो एक वस्तु को लौटाता है जो कि है begin()और end()जो कुंजियों और मूल्यों पर पुनरावृत्तियां प्रदान करती हैं।
बेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.