如何将map<string,map<int,int>>的内容打印到控制台?

3

如何打印嵌套映射的内容?我正在统计文件中单词出现的次数,按行号和每行出现次数报告。单词、行号和每行的出现次数存储在以下容器中:

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

然而,我对语法不确定。使用以下代码打印列出所有单词的外部映射,但无法弄清如何同时打印内部值(每行出现次数和编号)。我认为可以在for循环中内联包含它,但是我无法弄清楚如何操作:

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

我正在尝试获得类似于以下输出的结果:
(word: 行号:出现次数, 行号:出现次数, ...)
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
.
.
.

2
在循环内部,执行 map<int, int> const &the_map = it->second;,然后像处理 tokens 一样迭代 the_map - M.M
迭代内部有什么问题? - László Papp
顺便提一下,使用 const_iterator 而不是 iterator - M.M
在编辑中,t->second 应该改为 it->second - M.M
请勿在问题中添加解决方案,如果已经在所选答案中提供。这只是不必要的重复,并且一旦更新其中一个而没有为另一个进行更新,它们就会失去同步。 - László Papp
3个回答

5

其实很简单。

你只需使用 it->second 获取内部映射,然后以同样的方式进行迭代。

因此,你可以这样编写:

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

如果您有C++11支持,可以编写类似以下的内容:
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;
}

1
这在C++11中会更加优雅 :) - M.M
1
@MattMcNabb:虽然不是所有地方都支持C++11,但无论如何都提供了解决方案。 - László Papp
绝对喜欢自动版本,但也很高兴看到类型,因为我不太理解迭代器,并且正在努力提高它们的使用。在尝试这样做时,我在 it2->second 之前的流输出运算符上遇到了错误,显示“没有匹配这些操作数的 << 运算符”。你有什么想法吗? - CGutz
1
我犯了一个错误,使用了"->"而不是"."来进行自动版本控制。不过,我会在收集更多反馈后稍后修复它,因为它已经被编辑了好几次了。此外,逗号后面还缺少一个空格。 :) - László Papp
1
我无法想象在没有打字错误的情况下发生这种事情。 - László Papp
显示剩余2条评论

1

C++17

自从C++17,您可以使用基于范围的for循环结构化绑定来迭代映射。 这样,lpapp的C++11解决方案的可读性可以进一步改善,如下所示:

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

注意:我承认,打印逗号的检查有点混乱。如果您正在寻找更好的解决方案,您可能需要查看这个问答在Coliru上的代码

0

由于我们只是打印元素,而不是修改它,因此我会更多地使用 const,(a) const 引用和 (b) const 迭代器

另外,在 C++11 之前,为复杂类型定义 typedef 有助于简化代码。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接