如何合并2个std::映射,并在第三个映射中输出结果

How to merge 2 std::maps, and output the result in a 3rd map

本文关键字:映射 三个 结果 输出 2个 合并 std 何合并      更新时间:2023-10-16

编辑原始问题,因为我想问关于std::map而不是std::vector的问题。我的错误。很抱歉

我的数据实际上在2个std::map s中。我想将两个映射合并到第三个映射中。

我的第一个和第二个映射包含具有相同关键字的条目。所以我也想将这些键下的数据合并到我的第三个映射中。

那么,如果我使用std::merge,我会丢失第一个或第二个映射公共条目中的数据吗?正如我所提到的,两个地图中都有共同的数据(值)?

顺序容器的信息

如果对vector(或其他顺序容器,如listdeque)进行了排序,则可以使用std::set_union。有一个std::merge,以防您想保存重复的

从链接页面获取的代码

#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
    std::vector<int> v1 = {1, 2, 3, 4, 5}; 
    std::vector<int> v2 = {      3, 4, 5, 6, 7}; 
    std::vector<int> dest1;
    std::set_union(v1.begin(), v1.end(),
                   v2.begin(), v2.end(),                  
                   std::back_inserter(dest1));
    for (const auto &i : dest1) {
        std::cout << i << ' ';
    }   
    std::cout << 'n';
}

输出:1 2 3 4 5 6 7

关联容器的信息

您可以使用insert方法向map(或set及其无序对应项)添加唯一密钥。原始映射中已经存在的任何密钥都不会被替换(在multisetmultimap中,将添加重复的密钥,如果应该避免,请使用之前讨论过的set_union)。

映射示例(忽略具有重复键的条目)

#include <map>
#include <iostream>
int main()
{
    std::map<int, int> v1 = {{1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}};
    std::map<int, int> v2 = {                {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2}};
    std::map<int, int> dest1 = v1;
    dest1.insert(v2.begin(), v2.end());
    for (const auto &i : dest1) {
        std::cout << i.first << ':' << i.second << ' ';
    }
    std::cout << 'n';
}

输出(第一个数字是关键,第二个数字——它来自哪个地图):1:1 2:1 3:1 4:1 5:1 6:2 7:2

如果切换映射(在开始时将dest1设置为v2的副本,并插入v1的值),则输出将为:1:1 2:1 3:2 4:2 5:2 6:2 7:2

多映射示例(两个映射中的条目都保留)

#include <map>
#include <iostream>
int main()
{
    std::map<int, int> v1 = {{1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}};
    std::map<int, int> v2 = {                {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2}};
    std::multimap<int, int> dest1 {v1.begin(), v1.end()};
    dest1.insert(v2.begin(), v2.end());
    for (const auto &i : dest1) {
        std::cout << i.first << ':' << i.second << ' ';
    }
    std::cout << 'n';
}

输出:1:1 2:1 3:1 3:2 4:1 4:2 5:1 5:2 6:2 7:2

请注意,不能像使用贴图那样使用multimap。例如,operator[]不可用。您需要使用insert来添加条目,并使用lower_boundequal_range成员函数来提取条目。

这就是std::merge的作用:

std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(v3));

我相信您想要的是既能合并映射,又能合并映射的内容。

template<class Map, class Merge>
Map careful_merge( Map lhs, Map const& rhs, Merge&& merge ) {
  for (auto&& rhs_entry : rhs) {
    auto lhs_it = lhs.find(rhs_entry.first);
    if (lhs_it == lhs.end()) {
      lhs.insert( rhs_entry );
      continue;
    }
    auto& lhs_value = lhs_it.second;
    lhs_value = merge(std::move(lhs_value), rhs.second);
  }
  return lhs;
}

这是一个助手函数,它接受两个关联容器,如果值在两个容器中,则调用merge

假设您有一个std::map< std::string, std::vector<int> >,并希望合并它们,以便结果将映射的附加到向量。然后:

using my_map = std::map< std::string, std::vector<int> >;
my_map a, b; // fill these somehow.
my_map result = careful_merge( a, b,
  [](std::vector<int> lhs, std::vector<int> const& rhs ) {
    lhs.insert(lhs.end(), rhs.begin(), rhs.end());
    return std::move(lhs);
  }
);

我们完了。

左侧或右侧唯一的条目永远不会合并,只是逐字复制到输出中。

假定有效的移动语义。

它既适用于有序映射,也适用于无序映射。它不适用于套装。我建议不要在多地图上使用它,即使它有效(我不确定),因为它不是为他们设计的。

请注意,从C++17开始,现在有一个std::map::merge(other_map)方法。

请参阅https://en.cppreference.com/w/cpp/container/map/merge