C ++ 맵에서 키 반복
C ++ 맵 쌍이 아닌 키를 반복하는 방법이 있습니까?
"실제"반복기가 반환하는 값을 정말로 숨겨야하는 경우 (예를 들어 표준 알고리즘과 함께 키 반복기를 사용하여 쌍 대신 키에서 작동하도록하려는 경우) Boost의 transform_iterator .
[팁 : 새 클래스에 대한 Boost 문서를 볼 때 먼저 끝에있는 "예제"를 읽으십시오. 그런 다음 나머지 부분이 무엇에 대해 이야기하고 있는지 알아낼 스포츠 기회가 있습니다. :-)]
지도는 연관 컨테이너입니다. 따라서 iterator는 한 쌍의 key, val입니다. 키만 필요한 경우 쌍의 값 부분을 무시할 수 있습니다.
for(std::map<Key,Val>::iterator iter = myMap.begin(); iter != myMap.end(); ++iter)
{
Key k = iter->first;
//ignore value
//Value v = iter->second;
}
편집 : : 키만 외부에 노출하려는 경우지도를 벡터 또는 키로 변환하고 노출 할 수 있습니다.
C ++ 11에서는 반복 구문이 간단합니다. 여전히 쌍을 반복하지만 키에만 액세스하는 것은 쉽습니다.
#include <iostream>
#include <map>
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";
}
}
부스트없이
해당 맵에 대한 STL 반복기를 확장하면됩니다. 예를 들어 문자열을 정수로 매핑하는 경우 :
#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());
C ++ 17 을 사용하면 범위 기반 for 루프 내 에서 구조화 된 바인딩을 사용할 수 있습니다 ( 그에 따라 John H.의 답변을 적용 함 ).
#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
변수 에 대해 경고 할 수 있습니다 ! 사용하지 않는 변수에 대한 컴파일 시간 경고는 내 마음에있는 어떤 프로덕션 코드에도 적용되지 않습니다. 따라서 특정 컴파일러 버전에는 적용되지 않을 수 있습니다.
Ian이 언급 한보다 일반적인 템플릿 솔루션 아래에서 ...
#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의 transform_iterator를 사용하여 수행하는 방법의 예입니다.
#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
필요하지 않다, 즉,이 범위의 루핑을위한 키 (제 1 예) 또는 값 (예를 들어 초)에 걸쳐 루프를 얻을 수있다
#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;
.....
}
키만 반환하는 반복기가 필요한 경우 원하는 인터페이스를 제공하는 자체 클래스에서 맵의 반복기를 래핑해야합니다. 기존 헬퍼 구성을 사용하여 여기 와 같이 처음부터 새 반복기 클래스를 선언 할 수 있습니다 . 이 답변 은 Boost를 사용 transform_iterator
하여 값 / 키 만 반환하는 반복기를 래핑하는 방법을 보여줍니다 .
당신은 할 수 있습니다
- 사용자 지정 반복기 클래스를 만들고
std::map<K,V>::iterator
- 사용
std::transform
당신의map.begin()
에map.end()
A를boost::bind( &pair::second, _1 )
펑 - 루프로
->second
반복하는 동안 멤버를 무시하십시오for
.
This answer is like rodrigob's except without the BOOST_FOREACH
. You can use c++'s range based for instead.
#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;
}
}
I know this doesn't answer your question, but one option you may want to look at is just having two vectors with the same index being "linked" information..
So in..
std::vector<std::string> vName;
std::vector<int> vNameCount;
if you want the count of names by name you just do your quick for loop over vName.size(), and when ya find it that is the index for vNameCount that you are looking for.
Sure this may not give ya all the functionality of the map, and depending may or may not be better, but it might be easier if ya don't know the keys, and shouldn't add too much processing.
Just remember when you add/delete from one you have to do it from the other or things will get crazy heh :P
Without Boost, you could do it like this. It would be nice if you could write a cast operator instead of getKeyIterator(), but I can't get it to compile.
#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());
}
}
For posterity, and since I was trying to find a way to create a range, an alternative is to use boost::adaptors::transform
Here's a small example:
#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;
}
If you want to iterate over the values, use t.second
in the lambda.
Lots of good answers here, below is an approach using a couple of them which lets you write this:
void main()
{
std::map<std::string, int> m { {"jim", 1000}, {"sally", 2000} };
for (auto key : MapKeys(m))
std::cout << key << std::endl;
}
If that's what you always wanted, then here is the code for 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);
}
I've adopted Ian's answer to work with all map types and fixed returning a reference for 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;
}
};
참고URL : https://stackoverflow.com/questions/1443793/iterate-keys-in-a-c-map
'program story' 카테고리의 다른 글
앱이 실행되는 동안 Android 비활성화 화면 시간 초과 (0) | 2020.08.08 |
---|---|
ModelState.IsValid == false, 그 이유는 무엇입니까? (0) | 2020.08.08 |
확장 구성을 편집 한 후 VScode를 다시 시작하는 방법은 무엇입니까? (0) | 2020.08.07 |
Switch Statement Fallthrough… 허용되어야합니까? (0) | 2020.08.07 |
메소드 서명의 Java "매개 변수"? (0) | 2020.08.07 |