【问题标题】:How can I merge two STL maps?如何合并两个 STL 映射?
【发布时间】:2011-04-08 01:44:47
【问题描述】:

如何将两个 STL 映射合并为一个?它们都具有相同的键和值类型 (map<string, string>)。如果键重叠,我想优先选择其中一张地图。

【问题讨论】:

    标签: c++ merge stl maps stdmap


    【解决方案1】:

    假设你想保留mapA中的元素,并合并mapBmapA中没有key的元素:

    mapA.insert(mapB.begin(), mapB.end())
    

    我想你会做你想做的。

    (编辑:如果您使用的是 C++17 或更高版本,请考虑以下答案:https://stackoverflow.com/a/56594603/118150

    工作示例:

    #include <iostream>
    #include <map>
    
    void printIt(std::map<int,int> m) {
        for(std::map<int,int>::iterator it=m.begin();it!=m.end();++it)
            std::cout << it->first<<":"<<it->second<<" ";
        std::cout << "\n";
    }
    
    int main() {
        std::map<int,int> foo,bar;
        foo[1] = 11; foo[2] = 12; foo[3] = 13;
        bar[2] = 20; bar[3] = 30; bar[4] = 40;
        printIt(foo);
        printIt(bar);
        foo.insert(bar.begin(),bar.end());
        printIt(foo);
        return 0;
    }
    

    输出:

    :!./insert
    1:11 2:12 3:13
    2:20 3:30 4:40
    1:11 2:12 3:13 4:40
    

    【讨论】:

    • 如果键匹配,我看不出这不会覆盖 mapA 中的重复项。如果我只是说 mapB 是我的“首选”地图,我认为我可以使用它。这样,如果它是重复的,那么 mapB 中的键将是最终在新地图(现在是 mapA)中结束的那个。这听起来是正确的还是我误解了当有重复 E 时插入的作用?
    • Insert 不会覆盖已有的元素,当key发生冲突时,已经存在的元素优先。
    • 这有多复杂?是否为 n log(n),其中 n 是源映射中的元素数。还是可以降低复杂度(合并两棵红黑树)?
    • 标准说复杂度是 n log(n)(来源:cppreference)
    • @galinette 不完全是,它是 O(n log(n+m)) 其中 n 是源范围的大小(在这种情况下,实际上是源映射的大小),而 m是目标地图的大小。 (在源范围按目标的value_comp() 排序的特殊情况下,它可以实现为 O(n (1 + log(m/(1+n))) + log(m)),但是标准没有强制要求。)
    【解决方案2】:

    C++17

    John Perry's answer 中所述,由于C++17 std::map 提供了merge() 成员函数。 merge() 函数基于使用 insert() 为目标映射生成与 jkerian's solution 相同的结果,正如您从以下示例中看到的那样,我从 jkerian 借来的。我刚刚用C++11 和C++17 的一些特性更新了代码(例如using type aliasrange-based for loopstructured bindinglist initialization):

    using mymap = std::map<int, int>;
    
    void printIt(const mymap& m) {
        for (auto const &[k, v] : m)
            std::cout << k << ":" << v << " ";
        std::cout << std::endl;
    }
    
    int main() {
        mymap foo{ {1, 11}, {2, 12}, {3, 13} };
        mymap bar{ {2, 20}, {3, 30}, {4, 40} };
        printIt(foo);
        printIt(bar);
        foo.merge(bar);
        printIt(foo);
        return 0;
    }
    

    输出:

    1:11 2:12 3:13
    2:20 3:30 4:40
    1:11 2:12 3:13 4:40

    如您所见,merge() 在键重叠时也会优先考虑目标映射foo。如果你想反过来,那么你必须打电话给bar.merge(foo);

    但是,使用insert()merge() 对源映射的影响有所不同。 insert() 函数将新条目添加到目标映射中,而 merge() 将条目从源映射中移出。这意味着对于上面的示例,insert() 不会改变bar,但merge()bar 中删除4:40,因此只有2:203:30 保留在bar 中。

    注意:为了简洁起见,我重用了 jkerian 中使用 map&lt;int, int&gt; 的示例,但 merge() 也适用于您的 map&lt;string, string&gt;

    Code on Coliru

    【讨论】:

      【解决方案3】:

      请注意,从 C++17 开始,有一个用于映射的 merge() 方法。

      【讨论】:

        【解决方案4】:

        根据 ISO/IEC 14882:2003,第 23.1.2 节,表 69,表达式 a.insert(i,j):

        pre: i,j 不是 a 的迭代器。插入范围内的每个元素 [i, j) 当且仅当没有元素的键等价于 具有唯一键的容器中该元素的键;

        由于 std::map 必须遵循这个限制,如果你想优先考虑一个映射中的“值”而不是另一个映射,你应该插入它。例如,

        std::map<int, int> goodKeys;
        std::map<int, int> betterKeys;
        
        betterKeys.insert(goodKeys.begin(), goodKeys.end());
        

        所以如果 goodKeys 和 betterKeys 中有任何等价的键,betterKeys 的“值”会被保留。

        【讨论】:

          【解决方案5】:

          如果你想将条目从一张地图复制到另一张地图,你可以使用std::mapinsert

          targetMap.insert(sourceMap.begin(), sourceMap.end());
          

          但请注意,insert 如果元素的键已经在 targetMap 中,则不会更新元素;这些项目将保持原样。要覆盖元素,您必须显式复制,例如:

          for(auto& it : sourceMap)
          {
              targetMap[it.first] = it.second;
          }
          

          如果您不介意丢失sourceMap 中的数据,另一种实现复制和覆盖的方法是将insert 目标放入源并将std::swap 结果:

          sourceMap.insert(targetMap.begin(), targetMap.end());
          std::swap(sourceMap, targetMap);
          

          交换后,sourceMap 将包含 targetMap 的旧数据,targetMap 将是两个映射的合并,优先考虑 sourceMap 的条目。

          【讨论】:

            猜你喜欢
            • 2019-04-11
            • 2011-05-29
            • 2016-06-08
            • 1970-01-01
            • 2018-08-23
            • 1970-01-01
            • 2022-12-14
            • 1970-01-01
            • 2017-09-25
            相关资源
            最近更新 更多