C ++지도 맵을 어떻게 반복 할 수 있습니까?


292

std::mapC ++에서 루프를 어떻게 반복 할 수 있습니까? 내지도는 다음과 같이 정의됩니다.

std::map< std::string, std::map<std::string, std::string> >

예를 들어 위 컨테이너에는 다음과 같은 데이터가 들어 있습니다.

m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";

이 맵을 반복하고 다양한 값에 액세스하려면 어떻게해야합니까?


25
현대적인 C ++에 대한 Riot의 대답을 받아들이는 것을 고려할 수도 있습니다 .Google 직원에게는 그렇게하십시오.
Sergio Basurco

지도의지도가 최소, 완전, 검증 가능한 예 라고 확신 할 수는 없지만 요점은 확실합니다 !
davidhood2

3
알림을 놓친 경우 chuckleplant의 의견을 반복하겠습니다. 현대적인 C ++에 대한 Riot의 답변을 수락하는 것을 고려할 수도 있습니다.
noɥʇʎԀʎzɐɹƆ

강아지의 대답은 더 다양하지만 Google 직원은 폭동의 수를 기준으로 Riot의 대답을 더 많이 원합니다.
Legion Daeth

답변:


563

오래된 질문이지만 나머지 답변은 C ++ 11부터 구식입니다. 원격 기반 for 루프를 사용 하고 간단하게 수행 할 수 있습니다.

std::map<std::string, std::map<std::string, std::string>> mymap;

for(auto const &ent1 : mymap) {
  // ent1.first is the first key
  for(auto const &ent2 : ent1.second) {
    // ent2.first is the second key
    // ent2.second is the data
  }
}

이전 버전보다 훨씬 깨끗해야하며 불필요한 사본을 피해야합니다.

주석을 참조 변수의 명시 적 정의로 바꾸는 것이 좋습니다 (사용하지 않으면 최적화됩니다).

for(auto const &ent1 : mymap) {
  auto const &outer_key = ent1.first;
  auto const &inner_map = ent1.second;
  for(auto const &ent2 : inner_map) {
    auto const &inner_key   = ent2.first;
    auto const &inner_value = ent2.second;
  }
}

13
답변을 관련성있게 유지하기위한 제안-이 방법이 정상에 가까워 질 수 있기를 바랍니다. 아마도 이것을 수락 된 답변으로 편집하는 것이 적절할까요? (이것은 TeX.SX에서하는 일이지만 SO는 다른 문화입니다.)
Sean Allred

2
그냥 빨리 질문, 쓰기의 결정에 어떤 관련성이 const후는 auto? 순수한 미학인가요?
Parham

6
지정된 유형 앞뒤의 @Parham const는 선호의 문제이지만 포인터를 사용하는 상황에서 더 명확하게하기 때문에 오른쪽에 유지하기로 선택합니다. 예를 들어 모두를 사용하는 경우 int const *xint *const x같이 당신은 그것을 쓸 수 int const *const x보다 IMO 훨씬 명확하다 const int *const x. 그러나 왼쪽에서 오른쪽으로 구문 분석되었으므로 효과는 동일합니다. 이 질문에 대한 답변을 참조하십시오 : stackoverflow.com/questions/5503352/const-before-or-const-after
Riot

2
자동 const & ent2에서 &는 무엇을 의미합니까?
Tanner Summers

5
값으로 액세스하면 각 요소를 복사하는 비 효율성이 추가되므로 @TannerSummers; 또한 내용을 수정하려면 값이 아닌 참조 (또는 포인터)로 요소에 액세스해야합니다.
Riot

308

반복자를 사용할 수 있습니다.

typedef std::map<std::string, std::map<std::string, std::string>>::iterator it_type;
for(it_type iterator = m.begin(); iterator != m.end(); iterator++) {
    // iterator->first = key
    // iterator->second = value
    // Repeat if you also want to iterate through the second map.
}

10
그가 맵을 수정하지 않는 한 const_iterator를 사용하는 것이 좋습니다.
Michael Aaron Safyan

28
증분 할 때 불필요한 사본을 피하기 때문에 반복자 ++보다 ++ 반복자를 수행하는 것이 더 효율적입니다.
Game_Overture

19
auto를 사용하면 C ++ 11의 루프가 크게 단순화됩니다.for(auto iterator = m.begin(); iterator != m.end(); iterator++)
Gerard

127
이것은 c ++ 11에서는 구식입니다. 그냥 사용하십시오 (자동 iter : mymap)
Anonymous Entity

37
c ++ 11의 경우 잠재적 사본을 피하기 위해 (auto & iter : mymap)을 사용해야합니다.
dev_nut

60
for(std::map<std::string, std::map<std::string, std::string> >::iterator outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
    for(std::map<std::string, std::string>::iterator inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
        std::cout << inner_iter->second << std::endl;
    }
}

또는 C ++ 0x에서 더 좋습니다 :

for(auto outer_iter=map.begin(); outer_iter!=map.end(); ++outer_iter) {
    for(auto inner_iter=outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter) {
        std::cout << inner_iter->second << std::endl;
    }
}

2
auto &를 사용하거나지도를 수정하지 않으면 const auto &도 사용해야합니다. 또한 비 멤버 begin () 및 end ()를 선호합니다 (예 : for (const auto & iter = begin (map); ...)).
Ela782

13
또는 더 간단합니다 : for (const auto & element : map) cout << element.second;
Ela782

26

C ++ 17 이상에서는 "구조적 바인딩"기능을 사용하여 단일 튜플 / 쌍을 사용하여 다른 이름으로 여러 변수를 정의 할 수 있습니다. 예:

for (const auto& [name, description] : planet_descriptions) {
    std::cout << "Planet " << name << ":\n" << description << "\n\n";
}

원래의 제안 (유명 비얀 스트로브 스트 룹, 허브 셔터와 가브리엘 도스 헤이스에 의해)은 재미 읽는 것입니다 (와 제안 된 구문은 이럴 더 직관적이다); 또한 표준에 대한 제안 은 지루하지만 실제로 들어갈 내용에 더 가깝습니다.


2
C ++ 17이 아직 "있지"않았음에도 불구하고 투표해야합니다. 사람들은 깨끗하고 안전한 코드를보다 쉽게 ​​작성할 수 있도록하여 C ++를 활성화하고 있습니다.
조나스

24

다음과 같이하십시오 :

typedef std::map<std::string, std::string> InnerMap;
typedef std::map<std::string, InnerMap> OuterMap;

Outermap mm;

...//set the initial values

for (OuterMap::iterator i = mm.begin(); i != mm.end(); ++i) {
    InnerMap &im = i->second;
    for (InnerMap::iterator ii = im.begin(); ii != im.end(); ++ii) {
        std::cout << "map[" 
                  << i->first 
                  << "][" 
                  << ii->first 
                  << "] =" 
                  << ii->second 
                  << '\n';
    }
}   

두 번째로 ++ i가 아닌 ++ ii가되어야합니다. :)
Slipstream

'/ n'은 결국 '\ n'이어야한다고 생각합니다.
Kenyakorn Ketsombut

그럼 난이 C ++ 98 : 1을위한 좋은 방법입니다 나중에 가시 그들 확정적에 대한 정의를 사용했을
루도빅 Zenohate Lagouardette

12

C ++ 11 :

std::map< std::string, std::map<std::string, std::string> > m;
m["name1"]["value1"] = "data1";
m["name1"]["value2"] = "data2";
m["name2"]["value1"] = "data1";
m["name2"]["value2"] = "data2";
m["name3"]["value1"] = "data1";
m["name3"]["value2"] = "data2";

for (auto i : m)
    for (auto j : i.second)
        cout << i.first.c_str() << ":" << j.first.c_str() << ":" << j.second.c_str() << endl;

산출:

name1:value1:data1
name1:value2:data2
name2:value1:data1
name2:value2:data2
name3:value1:data1
name3:value2:data2

2
이 답변이 stackoverflow.com/a/27344958/3658660과 어떻게 다른 가요? 그것이 어디에서나 복사한다는 사실을 제외하고.
hlscalon

1

std::map< std::string, std::map<std::string, std::string> >::const_iteratormap이 const 일 때 사용합니다 .


1
올바른 마진 뒤에 코드를 숨기는 것이 좋은 습관이 아닌 경우가 있습니다. 나는 그것이 더 안전하다는 것을 이해하지만 코드의 비전을 완전히 흐리게합니다. 가자 auto, 또는 vim을 사용하는 사람은 KO를 갈 것이다.
Ludovic Zenohate Lagouardette

0

으로 einpoklum 에 언급 된 그들의 대답 이후, C ++ (17) 당신은 또한 사용할 수 있습니다 선언을 결합 구조 . 편안한 방법으로 맵을 반복하는 완벽한 솔루션을 제공함으로써이를 확장하고 싶습니다.

int main() {
    std::map<std::string, std::map<std::string, std::string>> m {
        {"name1", {{"value1", "data1"}, {"value2", "data2"}}},
        {"name2", {{"value1", "data1"}, {"value2", "data2"}}},
        {"name3", {{"value1", "data1"}, {"value2", "data2"}}}
    };

    for (const auto& [k1, v1] : m)
        for (const auto& [k2, v2] : v1)
            std::cout << "m[" << k1 << "][" << k2 << "]=" << v2 << std::endl;

    return 0;
}

참고 1 : 지도를 채우기 위해 초기화 목록 ( C ++ 11 기능)을 사용했습니다. 고정 초기화를 간결하게 유지하는 데 편리한 경우가 있습니다.

참고 2 :m 루프 내에서 맵을 수정 하려면 const키워드 를 제거해야 합니다.

콜리 루 코드


0

첫 번째 해결책은 다음과 같이 range_based for loop 사용입니다.

참고 : range_expression유형이 std::map이면 range_declaration유형이 std::pair입니다.

for ( range_declaration : range_expression )      
  //loop_statement

코드 1 :

typedef std::map<std::string, std::map<std::string, std::string>> StringToStringMap;

StringToStringMap my_map;

for(const auto &pair1 : my_map) 
{
   // Type of pair1 is std::pair<std::string, std::map<std::string, std::string>>
   // pair1.first point to std::string (first key)
   // pair1.second point to std::map<std::string, std::string> (inner map)
   for(const auto &pair2 : pair1.second) 
   {
       // pair2.first is the second(inner) key
       // pair2.second is the value
   }
}

두 번째 해결책 :

코드 2

typedef std::map<std::string, std::string> StringMap;
typedef std::map<std::string, StringMap> StringToStringMap;

StringToStringMap my_map;

for(StringToStringMap::iterator it1 = my_map.begin(); it1 != my_map.end(); it1++)
{
    // it1->first point to first key
    // it2->second point to inner map
    for(StringMap::iterator it2 = it1->second.begin(); it2 != it1->second.end(); it2++)
     {
        // it2->second point to value
        // it2->first point to second(inner) key 
     }
 }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.