2011-01-30 9 views
266

Làm cách nào để lặp qua một số std::map trong C++? Bản đồ của tôi được định nghĩa là:Làm cách nào để lặp qua bản đồ bản đồ C++?

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

Ví dụ, đây chứa dữ liệu như thế này:

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

Làm thế nào tôi có thể lặp qua bản đồ này và truy cập vào các giá trị khác nhau?

+21

Bạn có thể xem xét chấp nhận câu trả lời của Riot cho C++ hiện đại, làm điều đó cho các googlers. –

+0

Không hoàn toàn chắc chắn rằng có bản đồ bản đồ sẽ là ví dụ [Tối thiểu, Hoàn thành, Có thể xác minh được] (http://stackoverflow.com/help/mcve) nhưng điểm được thực hiện! – davidhood2

+3

Trong trường hợp bạn bỏ lỡ thông báo, hãy để tôi lặp lại nhận xét của chuckleplant: ** Bạn có thể xem xét chấp nhận câu trả lời của Riot cho C++ hiện đại, làm điều đó cho các googlers. ** –

Trả lời

530

Cũ câu hỏi nhưng câu trả lời còn lại là lỗi thời như của C++ 11 - bạn có thể sử dụng ranged based for loop và chỉ cần thực hiện:

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 
    } 
} 

điều này sẽ sạch hơn nhiều so với các phiên bản trước và tránh các bản sao không cần thiết.

Một số ủng hộ thay thế cho ý kiến ​​với các định nghĩa rõ ràng của biến tham chiếu (mà có được tối ưu hóa lập tức nếu không sử dụng):

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

Đạo cụ để giữ các câu trả lời có liên quan - Tôi chỉ ước điều này có thể tăng lên gần hơn đến đỉnh. Có lẽ việc chỉnh sửa câu trả lời cho câu trả lời được chấp nhận sẽ phù hợp? (Đó là những gì chúng tôi làm trên TeX.SX, nhưng SO là một nền văn hóa khác.) –

+2

Chỉ là một câu hỏi nhanh, có liên quan gì đến quyết định viết 'const' sau 'auto' không? Nó hoàn toàn là thẩm mỹ? – Parham

+6

@Parham const trước hoặc sau một loại được chỉ định là một vấn đề ưu tiên, nhưng tôi chọn giữ nó ở bên phải vì nó làm cho nó rõ ràng hơn trong các tình huống mà con trỏ đang được sử dụng; ví dụ khi sử dụng cả '' 'int const * x''' và' '' int * const x''' bạn có thể viết nó là '' 'int const * const x''', IMO rõ ràng hơn nhiều so với' ' 'const int * const x'''. Nhưng nó chỉ được phân tích cú pháp từ trái sang phải để hiệu quả là như nhau. Xem câu trả lời cho câu hỏi này: http://stackoverflow.com/questions/5503352/const-before-or-const-after – Riot

304

Bạn có thể sử dụng trình lặp.

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. 
} 
+0

hoạt động tốt, nhưng làm cout << it_type-><< endl đầu tiên; cung cấp cho tôi lỗi dự kiến ​​biểu thức chính trước -> mã thông báo – Jack

+2

Đó là becaus it_type là loại và 'iterator' là biến. Lỗi của tôi. – Puppy

+0

Ah không phải lo lắng. Tôi nên phát hiện ra điều đó.Thanks anyway – Jack

58
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; 
    } 
} 

hoặc đẹp hơn trong 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; 
    } 
} 
+13

+1 để cung cấp cả hai phiên bản. Gotta yêu 'auto'. – Xeo

+2

Bạn nên sử dụng tự động &, hoặc nếu bạn không sửa đổi bản đồ, thậm chí const auto &. Ngoài ra, hãy chọn không phải là thành viên bắt đầu() và kết thúc(), tức là (const auto & iter = begin (map); ...). – Ela782

+13

Hoặc thậm chí đơn giản hơn: cho (const auto & element: map) cout << element.second; – Ela782

23

Làm như thế này:

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'; 
    } 
} 
+0

Trong thứ hai cho nó nên được + + ii không ++ i :) – Slipstream

+0

Tôi nghĩ rằng '/ n' nên là một '\ n' cuối cùng –

+0

Vâng tôi đã có thể sử dụng định nghĩa để undef chúng sau này bur đây là một cách tốt cho C++ 98 :) +1 –

1

sử dụng std::map< std::string, std::map<std::string, std::string> >::const_iterator khi bản đồ là const.

+1

Bạn biết , đôi khi không phải là thói quen tốt để ẩn mã đằng sau lề phải. Tôi hiểu nó an toàn hơn nhưng cũng hoàn toàn làm mờ tầm nhìn của mã. Đi '' 'auto''' bro, hoặc người dùng vim sẽ đi KO. –

11

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; 

đầu ra:

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

Câu trả lời này khác với http://stackoverflow.com/a/27344958/3658660 như thế nào? Ngoại trừ thực tế là nó làm bản sao ở khắp mọi nơi. –

20

Trong C++ 17, bạn sẽ có thể sử dụng "ràng buộc có cấu trúc" tính năng, cho phép bạn xác định nhiều biến , với các tên khác nhau, sử dụng một bộ/cặp đơn. Ví dụ:

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

Các original proposal (bằng uy tín Bjarne Stroustrup, Herb Sutter và Gabriel Dos Reis) là thú vị để đọc (và cú pháp được đề xuất là IMHO trực quan hơn); đó cũng là số proposed wording for the standard mà nhàm chán để đọc nhưng gần gũi hơn với những gì thực sự sẽ đi vào.

+2

Điều này rất đẹp Tôi cần phải bỏ phiếu mặc dù C++ 17 không được "có" khá được nêu ra. Người đàn ông, họ đang thực sự làm sống lại C++ bằng cách làm cho nó dễ dàng hơn để viết mã sạch và an toàn. – Jonas

+0

@ Jonas: C++ 17 giờ là "ở đó". – einpoklum