2009-03-25 16 views
29

पर एक std :: कुंजी का सेट कैसे प्राप्त कर सकता हूं मैं आज सुबह एक एल्गोरिदम लिख रहा था और मैं एक जिज्ञासु स्थिति में भाग गया। मेरे पास दो std::map एस है। मैं प्रत्येक की चाबियों के सेट पर एक सेट चौराहे करना चाहता हूं (यह पता लगाने के लिए कि कौन सी कुंजी दोनों मानचित्रों के लिए आम हैं)। भविष्य में किसी बिंदु पर, मुझे लगता है कि यह संभावना है कि मैं यहां भी सेट घटाव करना चाहूंगा। सौभाग्य से, एसटीएल में उन दोनों परिचालनों के लिए कार्य शामिल हैं। समस्या यह है कि, मुझे std::map से बाहर की कुंजियों का std::set नहीं मिल रहा है। क्या इसे करने का कोई तरीका है? मैं, कुछ के लिए देख रहा हूँ कि यह आसान होगा जैसे कि यह जावा में है:मैं std :: map

std::set<Foo> keys = myMap.getKeySet(); 

मेरे समझ है कि मैं नक्शे में iterators पर सीधे std::set_intersection() फ़ंक्शन का उपयोग नहीं कर सकते क्योंकि नक्शे std::pair वस्तुओं के बजाय का पर्दाफाश है बस चाबियाँ। साथ ही, मुझे नहीं लगता कि मानचित्र आदेश की गारंटी देता है। मुझे std::multimap एस की एक जोड़ी पर भी यही ऑपरेशन करने में दिलचस्पी है, अगर इससे कोई फर्क पड़ता है।

संपादित: (MSVC++ 6), निफ्टी टेम्पलेट चाल है कि को बढ़ावा देने में उपलब्ध हैं के सबसे अधिक इस्तेमाल नहीं किया जा सकता मैं संकलक मैं का उपयोग करने के लिए मजबूर कर रहा हूँ की उम्र के कारण शुरू में है कि उल्लेख करना भूल गया।

+2

एमएसवीसी ++ 6 पर छोड़ने के लिए इतनी जल्दी मत बनें - यह प्रश्न देखें http://stackoverflow.com/questions/252492/whats-the-latest-version-of-boost-compatible-with-vc6 –

+0

मानचित्र –

उत्तर

6

आप एक इटरेटर है कि केवल कुंजी (और नहीं मान) रिटर्न लौटने के लिए बहुमुखी बढ़ावा :: transform_iterator का उपयोग कर सकते अपडेट किया गया। देखें How to retrieve all keys (or values) from a std::map and put them into a vector?

+0

यह एक सही समाधान की तरह लगता है, लेकिन मुझे शक है कि यह मेरे लिए संकलित होगा ... प्रश्न में मेरा संपादन देखें। – rmeador

2

आप बस एक ही सेट में प्रत्येक कुंजी को जोड़ सकते हैं और जोड़ सकते हैं। सेट और मानचित्र दोनों आदेश दिए जाते हैं, अनियंत्रित वेरिएंट नहीं होते हैं।

+1

क्रम में कुंजी रखता है यह अनिवार्य रूप से मैं पहले से ही कर रहा हूं। मैंने सोचा कि कुछ बेहतर तरीका हो सकता है, जहां "बेहतर" या तो "अधिक मानक" या "बेहतर प्रदर्शन" होता है। – rmeador

14

जो आप मूल रूप से चाहते हैं वह एक प्रति है, क्योंकि std :: map कुंजी को std :: set में नहीं रखता है। std :: प्रतिलिपि मानती है कि मान प्रकार संगत हैं, जो यहां मामला नहीं है। Std :: map :: value_type एक std :: जोड़ी है। आप केवल जोड़ी के पहले भाग की प्रतिलिपि बनाना चाहते हैं, जिसका अर्थ है कि आपको std :: transform की आवश्यकता है। अब, चूंकि आप सेट पर एक insert_iterator का उपयोग करेंगे, ऑर्डर कोई फर्क नहीं पड़ता। Std :: set प्रविष्टि को सॉर्ट करेगा, भले ही नक्शा पहले ही सॉर्ट हो गया हो।

[संपादित करें] कोड आसान हो सकता है। मेरे सिर का शीर्ष, संकलित नहीं।

std::transform(MyMap.begin(), MyMap.end(), 
    std::inserter(MySet, MySet.end()), 
    boost::bind(&std::pair<Key,Value>::first, _1)); 

यदि आपको एसजीआई का चयन 1 है, तो आपको बूस्ट :: बाइंड की आवश्यकता नहीं है।

[संपादित करें] के लिए सी ++ 14

std::transform(MyMap.begin(), MyMap.end(), 
    std::inserter(MySet, MySet.end()), 
    [](auto pair){ return pair.first; }); 
+0

मैं जो कह रहा हूं उसका काफी पालन नहीं कर सकता, लेकिन ऐसा लगता है कि यह संभवतः "सही" समाधान है। यह rlbond के जवाब से भी बहुत अधिक जटिल (ध्वनि) है (जो मैं पहले से कर रहा हूं)। क्या आप उदाहरण कोड प्रदान कर सकते हैं? धन्यवाद। – rmeador

+0

मुझे केवल एक तर्क लेने वाले इंसर्टर() के एक संस्करण के बारे में पता नहीं है। और दो-तर्क संस्करण का उपयोग करना एक अच्छी बात होगी क्योंकि यह सेट के "संकेत के साथ सम्मिलित करें" ऑपरेशन का उपयोग करता है, इस तथ्य का लाभ उठाते हुए कि मानचित्र के तत्वों को क्रमबद्ध किया गया है। "std :: inserter (माईसेट, MySet.end())"। –

+0

यूप, बैक_इन्सेटर एक-बहस है। फिक्स्ड। – MSalters

12

मानचित्र गारंटी आदेश है; यही कारण है कि इसे sorted associative container कहा जाता है। आप एक कस्टम तुलनित्र फ़ंक्शन के साथ set_intersection का उपयोग कर सकते हैं, दूसरा संस्करण here सूचीबद्ध है।

तो, जैसे

bool your_less(const your_map::value_type &v1, const your_map::value_type &v2) 
{ return v1.first < v2.first; } 

set_intersection(m1.begin(), m1.end(), m2.begin(), m2.end(), your_output_it, your_less); 

कुछ चाल करना चाहिए। (बूस्ट :: लैम्ब्डा और अस्थायी फ़ंक्शन लिखने से बचने के लिए बाध्य करना भी संभव है।)

जोड़े पर डिफ़ॉल्ट ऑपरेटर < दोनों घटकों की तुलना करता है। चूंकि आपको केवल जोड़ी (मानचित्र कुंजी) के पहले भाग में समकक्षता की आवश्यकता है, इसलिए आपको अपने स्वयं के तुलना ऑपरेटर को परिभाषित करने की आवश्यकता है जो इस तरह के संबंध प्रदान करता है (जो उपर्युक्त कार्य करता है)।

+3

किसी और के लिए यह कोशिश करने के लिए, मुझे विश्वास नहीं है कि यह काम करता है। मैंने इसका प्रयास किया और पाया कि मैं 'set_intersection' के असाइनमेंट ऑपरेशन से पहले गिर रहा था, '* _Dest ++ = * _First1 ++;'। कुंजी मानचित्र की जोड़ी में है, इसलिए असाइनमेंट विफल रहता है (एक भयानक समझ में नहीं आया टेम्पलेट त्रुटि के साथ)। – dlanod

6

अभ्यास में,

yourmap::const_iterator mi; 
set<key_type> k; 
for (mi = yourmap.begin(); mi != yourmap.end(); ++mi) 
    k.insert(mi->first); 
return k; 
+1

ओ (एन), प्रमुख मूल्यों की प्रतिलिपि बनाता है। – slacy

2

मैं आपके सवाल का here

के लिए अच्छा लिंक मिल गया और अपनी समस्या के लिए कुछ कोड है:

#include <iostream> 
    #include <map> 
    #include <set> 
    #include <iterator> 

    typedef std::map<std::string, int> MyMap; 

    // also known as select1st in SGI STL implementation 
    template<typename T_PAIR> 
    struct GetKey: public std::unary_function<T_PAIR, typename T_PAIR::first_type> 
    { 
     const typename T_PAIR::first_type& operator()(const T_PAIR& item) const 
     { 
      return item.first; 
     } 
    }; 

    int main(int argc, char** argv) 
    { 
     MyMap m1,m2; 

     m1["a"] = 1; 
     m1["b"] = 2; 
     m2["c"] = 3; 
     m2["b"] = 3; 

     std::set<std::string> s; 
     std::transform(m1.begin(), m1.end(), std::inserter(s, s.begin()), GetKey<MyMap::value_type>()); 
     std::transform(m2.begin(), m2.end(), std::inserter(s, s.begin()), GetKey<MyMap::value_type>()); 
     std::copy(s.begin(), s.end(), std::ostream_iterator<std::string>(std::cout, " ")); 
     std::cout << std::endl; 
     return 0; 
    } 
+0

इस तरह की एक ओवरकिल .... –

+0

हां, अगर आप एसजीआई चयन 1 या बूस्ट का उपयोग नहीं कर पा रहे हैं, तो आपको इसे स्वयं कोड करना होगा। मेरे लिए यह एक अच्छा अभ्यास है। –

2

सबसे अच्छा गैर एसजीआई, गैर बढ़ावा एसटीएल एल्गोरिदम-अनुकूल समाधान नक्शा का विस्तार करना है :: इटरेटर जैसे:

template<typename 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<typename map_type> 
key_iterator<map_type> key_begin(map_type& m) 
{ 
    return key_iterator<map_type>(m.begin()); 
} 
template<typename 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; 

     set<string> keys; 

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

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

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

यह प्रतिभा है। चूंकि मैं वास्तव में बस एक सेट नहीं चाहता हूं, लेकिन यहां तक ​​कि इटेटर इसे एक्सेस करने के लिए भी। इस समाधान के साथ मेरे पास कोई अतिरिक्त निर्भरता नहीं है जो मैं चाहता हूं :) – Paranaix

1

आप शायद, एक नक्शा जो केवल बढ़ावा :: एडेप्टर :: MAP_KEY का उपयोग कर कुंजी पैदावार के लिए एक इटरेटर बना सकते हैं boost::adapters::map_key documentation में उदाहरण देखें। ऐसा लगता है कि बूस्ट 1.43 में पेश किया गया है, और इसे सी ++ 2003 संगत माना जाता है, लेकिन मुझे विशेष रूप से वीसी ++ 6 के बारे में पता नहीं है, जो सी ++ 98 युग से है।

+0

क्या नक्शा_की एडाप्टर बूस्ट के संस्करण में उपलब्ध है जो वीसी 6 के साथ काम करता है? यदि नहीं, तो क्या आप इस अस्वीकरण को शामिल करने के लिए प्रश्न * संपादित कर सकते हैं? यदि हां, तो क्या आप पुराने दस्तावेज से लिंक कर सकते हैं, कहें, 1.34 युग? – chwarr

+0

@chwarr - इस बाधा को मेरे ध्यान में लाने के लिए धन्यवाद। ऐसा लगता है कि यह बूस्ट 1.43 से है, बूस्ट डॉक्स के सबसे पुराने संशोधन के रूप में ऐसा लगता है कि यह http: //www.boost है।संगठन/डॉक्टर/libs/1_43_0/libs/रेंज/डॉक्टर/एचटीएमएल/रेंज/संदर्भ/एडेप्टर/संदर्भ/map_keys.html। – YitzikC

1

zvrba से जवाब और dianot से टिप्पणी से ऊपर का निर्माण:

बस प्राप्त संग्रह एक नक्शे के बजाय जोड़े का एक वेक्टर होना है, और समस्या dianot द्वारा बताया खत्म हो गया है। तो, zvrba उदाहरण का उपयोग:

std::vector<std::pair<keytype, valtype>> v; 

set_intersection(m1.begin(), m1.end(), m2.begin(), m2.end(), 
std::back_inserter(v), [](std::pair<keytype, valtype> const & a, 
std::pair<keytype, valtype> const & b){return a.first < b.first;}); 

तो मध्यवर्ती प्रतियां या सेट हम कुशलतापूर्वक दो नक्शे के चौराहे प्राप्त कर सकते हैं का निर्माण बिना। यह निर्माण gcc5.3 के साथ संकलित करता है।

संबंधित मुद्दे