简体   繁体   中英

How can I print the content of map<string, map<int, int>> to cout?

How can I print the contents of a nested map? I am counting the number of times a word appears in a file, reporting it by line number and number of times per line. The words, lines, and occurrences per line are being stored in the following container:

map<string, map<int, int>> tokens;

However, I'm not sure on the syntax. I am printing the outer map that lists all of the words using the following code, but can't figure out how to print the inner values (the line number and number of times the word appears on each line) as well. I assume I can just include it inline in the for loop, but I can't figure out how:

for (map <string, map<int, int>>::iterator it = tokens.begin(); it != tokens.end(); ++it){
    cout << it->first << " : " << /* assume I can include another statement here to print the values? */ endl;
}

I am trying to get an output similar to this:

(word : line:occurrences, line:occurrences, ...)

about : 16:1, 29:1, 166:1, 190:1, 191:1
above : 137:1
accompanied : 6:1
across : 26:1
admit : 20:1
advancing : 170:1
.
.
.

It is actually pretty simple.

You just get the internal map with it->second, and you iterate through that the same way.

Thereby, you would write something like this:

for (map <string, map<int, int>>::iterator it = tokens.begin(); it != tokens.end(); ++it){
    cout << it->first << " : ";
    map<int, int> &internal_map = it->second;
    for (map<int, int>::iterator it2 = internal_map.begin(); it2 != internal_map.end(); ++it2){
        if (it2 != internal_map.begin())
            cout << ",";
        cout << it2->first << ":" << it2->second;
    }
    cout << endl;
}

You could write something like this if you have C++11 support:

for (auto it : tokens) {
    cout << it->first << " : ";
    map<int, int> &internal_map = it->second;
    for (auto it2: internal_map) {
        if (it2 != internal_map.begin())
            cout << ",";
        cout << it2->first << ":" << it2->second;
    }
    cout << endl;
}

C++17

Since C++17 you can use range-based for loops together with structured bindings for iterating over maps. This way, the readability of lpapp's C++11 solution can be further improved as follows:

for (auto const &[k1, v1] : tokens) {
    std::cout << k1 << " : ";
    for (auto const &[k2, v2] : v1) {
        if (&k2 != &v1.begin()->first)
            std::cout << ", ";
        std::cout << k2 << ":" << v2;
    }
    std::cout << std::endl;
}

Note: I admit, the check for printing a comma is a bit messy. If you are looking for a nicer solution, you might want to take a look at this Q&A .

Code on Coliru

Since we are only printing the elements, not modifying it, I would make more use of const , (a) const reference and (b) const iterator s.

Also, for pre-C++11, it helps to define typedef 's for complex types.

#include <string>
#include <map>
#include <iostream>
using namespace std;

typedef map<int, int> InnerMap;
typedef map<string, InnerMap> OuterMap;

void printClassic( OuterMap const & tokens ) {

    for( OuterMap::const_iterator cit = tokens.begin();
             cit != tokens.end(); ++cit ) {
        cout << cit->first << " : ";
        InnerMap const & imap = cit->second;
        for( InnerMap::const_iterator cit2 = imap.begin(); 
                 cit2 != imap.end(); ++cit2 ) {
        cout << cit2->first << ":" << cit2->second << ",";
        }
        cout << endl;
    }
}

void printCpp11( OuterMap const & tokens ) {
    for( auto const & cit : tokens ) {
        cout << cit.first << " : ";
        auto const & imap = cit.second;
        for( auto const & cit2 : imap ) {
            cout << cit2.first << ":" << cit2.second << ",";
        }
        cout << endl;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM