如何(有效地)以地图为值插入地图?

Posted

技术标签:

【中文标题】如何(有效地)以地图为值插入地图?【英文标题】:How to (efficiently) insert into a map with a map as value? 【发布时间】:2015-10-11 13:32:03 【问题描述】:

我正在编写一个 C++ 程序,逐行读取一个大文件,并将每个行信息(经过一些处理)插入到 unordered_map。

这是 unordered_map 的声明:

unordered_map<int, unordered_map<int, int> > entries;

我插入的是(这是在我处理文本文件的每一行的循环代码块中):

unordered_map<int, int> tmp;
tmp[y] = z;
entries[x] = tmp;

但事实证明,这在性能方面表现不佳。

我尝试创建一个pair&lt;int, pair&lt;int, int&gt;&gt; 并使用entries.insert(the_pair) 插入它,但我无法编译它(获取:no matching member function for call to 'insert')。

编辑: 程序看起来像这样:

ifstream ifile(path-to-file);
string line;
unordered_map<int, unordered_map<int, int> > entries;
while (getline(ifile, line)) 
    // some processing with line to find (int) x and (int) y 
    if (entries.find(x) == entries.end()) 
        auto iter_and_success = entries.emplace(x, unordered_map<int, int>);
        auto &tmp_m = iter_and_success.first->second;
        tmp_m[y] = 1;
    
    else 
        unordered_map<int, int> r = entries[x];
        if (r.count(y) == 0)
            entries[x][y] = (int) r.size() + 1;
    

【问题讨论】:

【参考方案1】:

我认为您最好的选择是将孩子unordered_map 移至父级:

entries[x] = std::move(tmp);

这样可以避免tmp 的额外副本。

另一种方法是在插入子地图后填充它。

 auto iter_and_success = entries.emplace(x, unordered_map<int, int>);
 auto& tmp = iter_and_success.first->second;
 tmp[y] = z;

实际上,如果x 发生多次(如果这是不受欢迎的行为 - 只需检查 bool 标志并采取相应措施),您实际上会将数据附加到子地图。


ifstream ifile(path-to-file);
string line;
unordered_map<int, unordered_map<int, int> > entries;
while (getline(ifile, line)) 
    // some processing with line to find (int) x and (int) y 

    // This will insert a new map only if x wasn't present
    auto iter_and_success = entries.emplace(x, unordered_map<int, int>);

    // This will be 1 if a new map was inserted
    auto value_to_insert = static_cast<int>(iter_and_success.first->second.size()) + 1;

    // This will do anything only if y wasn't present in sub-map
    iter_and_success.first->second.emplace(y, value_to_insert);

【讨论】:

使用第一种方法,不幸的是不会导致性能提升。有没有办法避免创建tmp unordered_map 并插入一对?在这种情况下,pair&lt;int, pair&lt;int,int&gt;&gt;? @Chris 我想知道你是如何测试的。好吧,第二种方法应该尽可能快地使用您拥有的数据结构。它基本上会实现您正在寻找的东西 - 没有不必要的分配/副本/等。请注意,在第二种情况下不会创建 tmp 无序映射,除非第一次插入键为 x(注意 auto&amp; tmp。由于您定义的数据结构,它必须至少创建一次。跨度> @Chris 如果没有有关您的访问模式的信息,很难进一步分析它。 我已经用程序的外观更新了我的 OP。测试只需使用 1000000 行的文件作为输入,然后打印我收集的信息。我正在使用time 函数测量经过的时间,我知道这很简单,但这就是我现在需要的。 @Chris 好的,这可以解决问题。我会更新我的答案。提示:unordered_map&lt;int, int&gt; r = entries[x]; 创建一个副本。

以上是关于如何(有效地)以地图为值插入地图?的主要内容,如果未能解决你的问题,请参考以下文章

Scala 以列表为键、字符串为值的地图展平

AS3:如何在 AS3 类中有效地存储平铺地图编辑器的数据

如何插入地图或矢量以生成 json 字符串 (jsoncpp)

如何在世界地图上准确地绘制半径以公里为单位的圆

如何以索引方式有效地存储所有 OpenStreetMap 数据?

如何使用地图将数据插入我的 Firebase 数据库?