C ++ मैप में Iterate कीज


121

क्या कुंजियों पर पुनरावृति करने का एक तरीका है, सी ++ नक्शे के जोड़े नहीं?


मूल्यों के लिए एक सूचनात्मक प्राप्त करने का विचार एसटीएल एल्गोरिदम में इसका उपयोग करना है, उदाहरण के लिए, दो मानचित्रों की कुंजियों का प्रतिच्छेदन। बूस्ट से जुड़े समाधान इसकी अनुमति नहीं देता है, क्योंकि यह बूस्टर इट्रेटर का उत्पादन करेगा। सबसे खराब जवाब को सबसे ज्यादा वोट मिले!

जवाबों:


70

यदि आपको वास्तव में उस मूल्य को छिपाने की आवश्यकता है जो "वास्तविक" इट्रेटर रिटर्न करता है (उदाहरण के लिए क्योंकि आप मानक एल्गोरिदम के साथ अपने कुंजी-इटरेटर का उपयोग करना चाहते हैं, ताकि वे जोड़े के बजाय कुंजियों पर काम करें), तो बूस्ट पर एक नज़र डालें transform_iterator

[टिप: जब एक नए वर्ग के लिए बूस्ट प्रलेखन को देखते हैं, तो सबसे पहले "उदाहरण" पढ़ें। फिर आपके पास यह पता लगाने का एक खेल मौका है कि पृथ्वी पर इसके बारे में बाकी क्या बात कर रहे हैं :-)]


2
बढ़ावा देने के साथ आप BOOST_FOREACH (const key_t key, the_map | बढ़ावा :: एडेप्टर :: map_keys) {do something} boost.org/doc/libs/1_50_0/libs.range/doc/html/range/reference/…
rodrigob लिख सकते हैं

120

नक्शा सहयोगी कंटेनर है। इसलिए, पुनरावृत्ति कुंजी, वैल की एक जोड़ी है। यदि आपको केवल कुंजियों की आवश्यकता है, तो आप जोड़ी से मूल्य भाग को अनदेखा कर सकते हैं।

for(std::map<Key,Val>::iterator iter = myMap.begin(); iter != myMap.end(); ++iter)
{
Key k =  iter->first;
//ignore value
//Value v = iter->second;
}

EDIT:: यदि आप केवल बाहर की चाबियों को उजागर करना चाहते हैं, तो आप नक्शे को वेक्टर या कुंजियों में बदल सकते हैं और उजागर कर सकते हैं।


लेकिन फिर बाहर वेक्टर के पुनरावृत्ति को उजागर करना वास्तव में बुरा होगा।
नवीन

पुनरावृति उजागर न करें। बस वेक्टर में चाबियाँ प्रदान करते हैं
ए जे।

5
आप इसके बजाय ऐसा करना चाह सकते हैं: const Key& k(iter->first);
strickli

17
दो बातें, इस वास्तव में इस सवाल का जवाब वह पहले से ही पता था और, अगर आप की तरह कुछ करना चाहता हूँ दूसरी बात इस प्रक्रिया में मदद नहीं करेगा की तलाश में नहीं किया गया था के साथ ओपी के सवाल का जवाब: std::vector<Key> v(myMap.begin(), myMap.end())
एंड्रियास मैग्यूसन

कुंजियों को वेक्टर में परिवर्तित न करें। एक नया वेक्टर बनाना पुनरावृत्ति के उद्देश्य को पराजित करता है, जिसे तेजी से माना जाता है और कुछ भी आवंटित नहीं किया जाता है। साथ ही, यह बड़े सेटों के लिए धीमा होगा।
केविन चेन

85

C ++ 11 के साथ पुनरावृत्ति सिंटैक्स सरल है। आप अभी भी जोड़े पर पुनरावृति करते हैं, लेकिन सिर्फ कुंजी तक पहुंचना आसान है।

#include <iostream>
#include <map>

int main()
{
    std::map<std::string, int> myMap;

    myMap["one"] = 1;
    myMap["two"] = 2;
    myMap["three"] = 3;

    for ( const auto &myPair : myMap ) {
        std::cout << myPair.first << "\n";
    }
}

29
मूल प्रश्न स्पष्ट रूप से "जोड़े नहीं" कहते हैं।
इयान

41

बिना बूस्ट के

आप बस उस नक्शे के लिए एसटीएल पुनरावृत्ति का विस्तार करके ऐसा कर सकते हैं। उदाहरण के लिए, किलों में तारों का मानचित्रण:

#include <map>
typedef map<string, int> ScoreMap;
typedef ScoreMap::iterator ScoreMapIterator;

class key_iterator : public ScoreMapIterator
{
  public:
    key_iterator() : ScoreMapIterator() {};
    key_iterator(ScoreMapIterator s) : ScoreMapIterator(s) {};
    string* operator->() { return (string* const)&(ScoreMapIterator::operator->()->first); }
    string operator*() { return ScoreMapIterator::operator*().first; }
};

अधिक सामान्य समाधान के लिए आप इस एक्सटेंशन को टेम्पलेट में भी प्रदर्शन कर सकते हैं।

वास्तव में की तरह आप एक ऐसी सूची इटरेटर का प्रयोग करेंगे छोड़कर आप बार-बार दोहराना नक्शा खत्म हो चुका है हों तब आप अपने इटरेटर का उपयोग begin()और end()

ScoreMap m;
m["jim"] = 1000;
m["sally"] = 2000;

for (key_iterator s = m.begin(); s != m.end(); ++s)
    printf("\n key %s", s->c_str());

16
+1: अंत में, कोई व्यक्ति जो "जोड़े नहीं" बिट पढ़ता है! चीयर्स, इसने मुझे युक्ति के माध्यम से खुदाई करने में समय बचाया है!
मार्क के कोवान

1
और टेम्प्लेटेड समाधान के नीचे, और मैंने वैल्यू इटरेटर जोड़ा।
डिवस्की

अपने प्रश्न को मेरे से जोड़ा।
इयान

template<typename C> class key_iterator : public C::iterator, आदि
गेब्रियल

38

C ++ 17 के साथ आप लूप के लिए रेंज-बेस्ड के अंदर एक स्ट्रक्चर्ड बाइंडिंग का उपयोग कर सकते हैं ( तदनुसार जॉन एच के जवाब को अडॉप्ट कर सकते हैं):

#include <iostream>
#include <map>

int main() {
    std::map<std::string, int> myMap;

    myMap["one"] = 1;
    myMap["two"] = 2;
    myMap["three"] = 3;

    for ( const auto &[key, value]: myMap ) {
        std::cout << key << '\n';
    }
}

दुर्भाग्य से C ++ 17 मानक के लिए आपको valueचर घोषित करने की आवश्यकता होती है , भले ही आप इसका उपयोग नहीं कर रहे हों ( std::ignoreजैसा std::tie(..)कि कोई काम नहीं करेगा , इस चर्चा को देखें )।

कुछ संकलक इसलिए आपको अप्रयुक्त valueचर के बारे में चेतावनी दे सकते हैं ! अप्रयुक्त चर के बारे में संकलन-समय की चेतावनी मेरे दिमाग में किसी भी उत्पादन कोड के लिए एक नहीं है। तो, यह कुछ संकलक संस्करणों के लिए लागू नहीं हो सकता है।


क्या आप इसे std :: सिद्धांत में अनदेखा नहीं कर सकते? क्या वास्तव में संकलित कोड में दक्षता को नुकसान पहुंचेगा या यह वास्तव में कुछ भी नहीं का मूल्यांकन करेगा? (मैं बंधन में नहीं है, बल्कि पाश के भीतर एक क्रिया के रूप में है)
KotoroShinoto

C ++ 17 के बाद से आप [[शायद_उपयोग]] का भी उपयोग कर सकते हैं। यह चेतावनी को दबा देता है। इस तरह:for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
arhuaco

15

और अधिक सामान्य templated समाधान के नीचे, जिसे इयान ने संदर्भित किया है ...

#include <map>

template<typename Key, typename Value>
using Map = std::map<Key, Value>;

template<typename Key, typename Value>
using MapIterator = typename Map<Key, Value>::iterator;

template<typename Key, typename Value>
class MapKeyIterator : public MapIterator<Key, Value> {

public:

    MapKeyIterator ( ) : MapIterator<Key, Value> ( ) { };
    MapKeyIterator ( MapIterator<Key, Value> it_ ) : MapIterator<Key, Value> ( it_ ) { };

    Key *operator -> ( ) { return ( Key * const ) &( MapIterator<Key, Value>::operator -> ( )->first ); }
    Key operator * ( ) { return MapIterator<Key, Value>::operator * ( ).first; }
};

template<typename Key, typename Value>
class MapValueIterator : public MapIterator<Key, Value> {

public:

    MapValueIterator ( ) : MapIterator<Key, Value> ( ) { };
    MapValueIterator ( MapIterator<Key, Value> it_ ) : MapIterator<Key, Value> ( it_ ) { };

    Value *operator -> ( ) { return ( Value * const ) &( MapIterator<Key, Value>::operator -> ( )->second ); }
    Value operator * ( ) { return MapIterator<Key, Value>::operator * ( ).second; }
};

सभी क्रेडिट इयान को जाते हैं ... धन्यवाद इयान।


11

आप map_keys की तलाश कर रहे हैं , इसके साथ आप चीजों को लिख सकते हैं

BOOST_FOREACH(const key_t key, the_map | boost::adaptors::map_keys)
{
  // do something with key
}

1
BOOST_FOREACH(const key_t& key, ...
स्ट्रिकली

5

यह बूस्ट के ट्रांसफॉर्म_टरेटर का उपयोग करके कैसे करें, इसका एक उदाहरण है

#include <iostream>
#include <map>
#include <iterator>
#include "boost/iterator/transform_iterator.hpp"

using std::map;
typedef std::string Key;
typedef std::string Val;

map<Key,Val>::key_type get_key(map<Key,Val>::value_type aPair) {
  return aPair.first;
}

typedef map<Key,Val>::key_type (*get_key_t)(map<Key,Val>::value_type);
typedef map<Key,Val>::iterator map_iterator;
typedef boost::transform_iterator<get_key_t, map_iterator> mapkey_iterator;

int main() {
  map<Key,Val> m;
  m["a"]="A";
  m["b"]="B";
  m["c"]="C";

  // iterate over the map's (key,val) pairs as usual
  for(map_iterator i = m.begin(); i != m.end(); i++) {
    std::cout << i->first << " " << i->second << std::endl;
  }

  // iterate over the keys using the transformed iterators
  mapkey_iterator keybegin(m.begin(), get_key);
  mapkey_iterator keyend(m.end(), get_key);
  for(mapkey_iterator i = keybegin; i != keyend; i++) {
    std::cout << *i << std::endl;
  }
}

4

जब कोई स्पष्टता beginऔर endआवश्यकता नहीं होती है, तो रेंज-लूपिंग के लिए, कुंजियों पर लूप (पहला उदाहरण) या मान (दूसरा उदाहरण) के साथ प्राप्त किया जा सकता है

#include <boost/range/adaptors.hpp>

map<Key, Value> m;

for (auto k : boost::adaptors::keys(m))
  cout << k << endl;

for (auto v : boost::adaptors::values(m))
  cout << v << endl;

1
std
Mordachai

3

आप ऐसा करना चाहते हैं?

std::map<type,type>::iterator iter = myMap.begin();
std::map<type,type>::iterator iter = myMap.end();
for(; iter != endIter; ++iter)
{
   type key = iter->first;  
   .....
}

हां, मुझे पता है, समस्या यह है कि मेरे पास एक वर्ग ए {पब्लिक: // है, मैं निजी नक्शे की कुंजियों पर एक पुनरावृत्ति उजागर करना चाहता हूं यहां निजी: मानचित्र <>;
बोगदान बालन

उस स्थिति में, मुझे लगता है कि आप std :: trasnform का उपयोग करके और नक्शे से केवल कुंजियाँ बनाकर एक std :: सूची बना सकते हैं। फिर आप सूची पुनरावृत्ति को उजागर कर सकते हैं क्योंकि सूची में अधिक तत्व डालने से मौजूदा पुनरावृत्तियों को अमान्य नहीं किया जाएगा।
नवीन

3

यदि आपको एक इटिअरेर की आवश्यकता है, जो आपके द्वारा अपनी इच्छित कक्षा में मैप के इटरेटर को लपेटने के लिए आवश्यक कुंजियाँ देता है जो वांछित इंटरफ़ेस प्रदान करता है। आप मौजूदा हेल्पर निर्माण का उपयोग करने के लिए यहां से एक नया पुनरावृत्ति वर्ग घोषित कर सकते हैं । यह उत्तर दिखाता है कि transform_iteratorबूस्टर को एक में लपेटने के लिए कैसे उपयोग किया जाए जो केवल मूल्यों / कुंजियों को लौटाता है।


2

आप ऐसा कर सकते हैं

  • एक कस्टम पुनरावृत्ति वर्ग बनाएँ, कुल मिलाकर std::map<K,V>::iterator
  • एक functor के साथ std::transformअपने map.begin()का उपयोग करेंmap.end()boost::bind( &pair::second, _1 )
  • लूप से ->secondपुनरावृत्ति करते समय सिर्फ सदस्य की उपेक्षा करें for

2

यह उत्तर रॉडरिगॉब की तरह है, सिवाय इसके BOOST_FOREACH। आप इसके बजाय c ++ की श्रेणी का उपयोग कर सकते हैं।

#include <map>
#include <boost/range/adaptor/map.hpp>
#include <iostream>

template <typename K, typename V>
void printKeys(std::map<K,V> map){
     for(auto key : map | boost::adaptors::map_keys){
          std::cout << key << std::endl;
     }
}

0

बूस्ट के बिना, आप इसे इस तरह से कर सकते हैं। यह अच्छा होगा यदि आप getKeyIterator () के बजाय एक कास्ट ऑपरेटर लिख सकते हैं, लेकिन मैं इसे संकलन करने के लिए नहीं कर सकता।

#include <map>
#include <unordered_map>


template<typename K, typename V>
class key_iterator: public std::unordered_map<K,V>::iterator {

public:

    const K &operator*() const {
        return std::unordered_map<K,V>::iterator::operator*().first;
    }

    const K *operator->() const {
        return &(**this);
    }
};

template<typename K,typename V>
key_iterator<K,V> getKeyIterator(typename std::unordered_map<K,V>::iterator &it) {
    return *static_cast<key_iterator<K,V> *>(&it);
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::unordered_map<std::string, std::string> myMap;
    myMap["one"]="A";
    myMap["two"]="B";
    myMap["three"]="C";
    key_iterator<std::string, std::string> &it=getKeyIterator<std::string,std::string>(myMap.begin());
    for (; it!=myMap.end(); ++it) {
        printf("%s\n",it->c_str());
    }
}

0

पोस्टरिटी के लिए, और जब से मैं एक सीमा बनाने का एक तरीका खोजने की कोशिश कर रहा था, एक विकल्प बढ़ावा का उपयोग करना है :: एडेप्टर रूपांतरण

यहाँ एक छोटा सा उदाहरण दिया गया है:

#include <boost/range/adaptor/transformed.hpp>
#include <iostream>
#include <map>

int main(int argc, const char* argv[])
{
  std::map<int, int> m;
  m[0]  = 1;
  m[2]  = 3;
  m[42] = 0;

  auto key_range =
    boost::adaptors::transform(
      m,
      [](std::map<int, int>::value_type const& t) 
      { return t.first; }
    ); 
  for (auto&& key : key_range)
    std::cout << key << ' ';
  std::cout << '\n';
  return 0;
}

यदि आप मूल्यों पर पुनरावृति करना चाहते हैं, t.secondतो लैम्ब्डा में उपयोग करें ।


0

नीचे बहुत सारे अच्छे उत्तर दिए गए हैं, उनमें से एक का उपयोग करके नीचे एक दृष्टिकोण है जो आपको यह लिखने देता है:

void main()
{
    std::map<std::string, int> m { {"jim", 1000}, {"sally", 2000} };
    for (auto key : MapKeys(m))
        std::cout << key << std::endl;
}

यदि आप हमेशा यही चाहते थे, तो यहाँ MapKeys () के लिए कोड है:

template <class MapType>
class MapKeyIterator {
public:
    class iterator {
    public:
        iterator(typename MapType::iterator it) : it(it) {}
        iterator operator++() { return ++it; }
        bool operator!=(const iterator & other) { return it != other.it; }
        typename MapType::key_type operator*() const { return it->first; }  // Return key part of map
    private:
        typename MapType::iterator it;
    };
private:
    MapType& map;
public:
    MapKeyIterator(MapType& m) : map(m) {}
    iterator begin() { return iterator(map.begin()); }
    iterator end() { return iterator(map.end()); }
};
template <class MapType>
MapKeyIterator<MapType> MapKeys(MapType& m)
{
    return MapKeyIterator<MapType>(m);
}

0

मैंने सभी मानचित्र प्रकारों के साथ काम करने के लिए इयान के उत्तर को अपनाया है और इसके लिए एक संदर्भ लौटाया है operator*

template<typename T>
class MapKeyIterator : public T
{
public:
    MapKeyIterator() : T() {}
    MapKeyIterator(T iter) : T(iter) {}
    auto* operator->()
    {
        return &(T::operator->()->first);
    }
    auto& operator*()
    {
        return T::operator*().first;
    }
};

-1

मुझे पता है कि यह आपके सवाल का जवाब नहीं देता है, लेकिन एक विकल्प जिसे आप देखना चाहते हैं, बस एक ही सूचकांक के साथ दो वैक्टर होते हैं, जो "अतिरिक्त" होते हैं।

तो में ..

std::vector<std::string> vName;

std::vector<int> vNameCount;

यदि आप नाम की गिनती चाहते हैं, तो आप केवल vName.size () पर लूप के लिए अपना त्वरित कार्य करते हैं, और जब आपको लगता है कि vNameCount का सूचकांक है जिसे आप खोज रहे हैं।

यकीन है कि यह आपको मानचित्र की सभी कार्यक्षमता प्रदान नहीं कर सकता है, और यह निर्भर करता है कि बेहतर हो सकता है या नहीं, लेकिन यह आसान हो सकता है यदि हां, आपको कुंजियों का पता नहीं है, और बहुत अधिक प्रसंस्करण नहीं जोड़ना चाहिए।

बस याद रखें कि जब आप एक को जोड़ते / हटाते हैं तो आपको इसे दूसरे से करना पड़ता है या चीजें पागल हो जाएंगी: पी

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.