क्या कुंजियों पर पुनरावृति करने का एक तरीका है, सी ++ नक्शे के जोड़े नहीं?
क्या कुंजियों पर पुनरावृति करने का एक तरीका है, सी ++ नक्शे के जोड़े नहीं?
जवाबों:
यदि आपको वास्तव में उस मूल्य को छिपाने की आवश्यकता है जो "वास्तविक" इट्रेटर रिटर्न करता है (उदाहरण के लिए क्योंकि आप मानक एल्गोरिदम के साथ अपने कुंजी-इटरेटर का उपयोग करना चाहते हैं, ताकि वे जोड़े के बजाय कुंजियों पर काम करें), तो बूस्ट पर एक नज़र डालें transform_iterator ।
[टिप: जब एक नए वर्ग के लिए बूस्ट प्रलेखन को देखते हैं, तो सबसे पहले "उदाहरण" पढ़ें। फिर आपके पास यह पता लगाने का एक खेल मौका है कि पृथ्वी पर इसके बारे में बाकी क्या बात कर रहे हैं :-)]
नक्शा सहयोगी कंटेनर है। इसलिए, पुनरावृत्ति कुंजी, वैल की एक जोड़ी है। यदि आपको केवल कुंजियों की आवश्यकता है, तो आप जोड़ी से मूल्य भाग को अनदेखा कर सकते हैं।
for(std::map<Key,Val>::iterator iter = myMap.begin(); iter != myMap.end(); ++iter)
{
Key k = iter->first;
//ignore value
//Value v = iter->second;
}
EDIT:: यदि आप केवल बाहर की चाबियों को उजागर करना चाहते हैं, तो आप नक्शे को वेक्टर या कुंजियों में बदल सकते हैं और उजागर कर सकते हैं।
const Key& k(iter->first);
std::vector<Key> v(myMap.begin(), myMap.end())
।
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";
}
}
आप बस उस नक्शे के लिए एसटीएल पुनरावृत्ति का विस्तार करके ऐसा कर सकते हैं। उदाहरण के लिए, किलों में तारों का मानचित्रण:
#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());
template<typename C> class key_iterator : public C::iterator
, आदि
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
चर के बारे में चेतावनी दे सकते हैं ! अप्रयुक्त चर के बारे में संकलन-समय की चेतावनी मेरे दिमाग में किसी भी उत्पादन कोड के लिए एक नहीं है। तो, यह कुछ संकलक संस्करणों के लिए लागू नहीं हो सकता है।
for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
और अधिक सामान्य 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; }
};
सभी क्रेडिट इयान को जाते हैं ... धन्यवाद इयान।
आप map_keys की तलाश कर रहे हैं , इसके साथ आप चीजों को लिख सकते हैं
BOOST_FOREACH(const key_t key, the_map | boost::adaptors::map_keys)
{
// do something with key
}
BOOST_FOREACH(const key_t& key, ...
यह बूस्ट के ट्रांसफॉर्म_टरेटर का उपयोग करके कैसे करें, इसका एक उदाहरण है
#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;
}
}
जब कोई स्पष्टता 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;
आप ऐसा करना चाहते हैं?
std::map<type,type>::iterator iter = myMap.begin();
std::map<type,type>::iterator iter = myMap.end();
for(; iter != endIter; ++iter)
{
type key = iter->first;
.....
}
यदि आपको एक इटिअरेर की आवश्यकता है, जो आपके द्वारा अपनी इच्छित कक्षा में मैप के इटरेटर को लपेटने के लिए आवश्यक कुंजियाँ देता है जो वांछित इंटरफ़ेस प्रदान करता है। आप मौजूदा हेल्पर निर्माण का उपयोग करने के लिए यहां से एक नया पुनरावृत्ति वर्ग घोषित कर सकते हैं । यह उत्तर दिखाता है कि transform_iterator
बूस्टर को एक में लपेटने के लिए कैसे उपयोग किया जाए जो केवल मूल्यों / कुंजियों को लौटाता है।
यह उत्तर रॉडरिगॉब की तरह है, सिवाय इसके 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;
}
}
बूस्ट के बिना, आप इसे इस तरह से कर सकते हैं। यह अच्छा होगा यदि आप 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());
}
}
पोस्टरिटी के लिए, और जब से मैं एक सीमा बनाने का एक तरीका खोजने की कोशिश कर रहा था, एक विकल्प बढ़ावा का उपयोग करना है :: एडेप्टर रूपांतरण
यहाँ एक छोटा सा उदाहरण दिया गया है:
#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
तो लैम्ब्डा में उपयोग करें ।
नीचे बहुत सारे अच्छे उत्तर दिए गए हैं, उनमें से एक का उपयोग करके नीचे एक दृष्टिकोण है जो आपको यह लिखने देता है:
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);
}
मैंने सभी मानचित्र प्रकारों के साथ काम करने के लिए इयान के उत्तर को अपनाया है और इसके लिए एक संदर्भ लौटाया है 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;
}
};
मुझे पता है कि यह आपके सवाल का जवाब नहीं देता है, लेकिन एक विकल्प जिसे आप देखना चाहते हैं, बस एक ही सूचकांक के साथ दो वैक्टर होते हैं, जो "अतिरिक्त" होते हैं।
तो में ..
std::vector<std::string> vName;
std::vector<int> vNameCount;
यदि आप नाम की गिनती चाहते हैं, तो आप केवल vName.size () पर लूप के लिए अपना त्वरित कार्य करते हैं, और जब आपको लगता है कि vNameCount का सूचकांक है जिसे आप खोज रहे हैं।
यकीन है कि यह आपको मानचित्र की सभी कार्यक्षमता प्रदान नहीं कर सकता है, और यह निर्भर करता है कि बेहतर हो सकता है या नहीं, लेकिन यह आसान हो सकता है यदि हां, आपको कुंजियों का पता नहीं है, और बहुत अधिक प्रसंस्करण नहीं जोड़ना चाहिए।
बस याद रखें कि जब आप एक को जोड़ते / हटाते हैं तो आपको इसे दूसरे से करना पड़ता है या चीजें पागल हो जाएंगी: पी