Marco Stramezzi
Marco Stramezzi

Reputation: 2271

Replace multiple elements in STL map

I need to replace multiple values inside an STL map but I haven't found anything useful in <algorithm>.

Pseudocode:

Input:
    map<type1, type2> m1;
    m1[k1] = v1;
    m1[k2] = v2;
    m1[k3] = v3;


    map<type1, type2> m2;
    m2[k1] = v5;
    m2[k3] = v4;

Action:
    merge(m1, m2)

Output:
    m1[k1] = v5;
    m1[k2] = v2;
    m1[k3] = v4;

The merge method should replace m1 values with m2 values when keys match.

I read documentation of merge but it seems to me not usable with maps.

Upvotes: 0

Views: 403

Answers (1)

Vittorio Romeo
Vittorio Romeo

Reputation: 93274

C++17 adds std::map::merge, which does what you want:

template<class C2>
void merge(std::map<Key, T, C2, Allocator>& source);

Attempts to extract ("splice") each element in source and insert it into *this using the the comparison object of *this. If there is an element in *this with key equivalent to the key of an element from source, then that element is not extracted from source. No elements are copied or moved, only the internal pointers of the container nodes are repointed. All pointers and references to the transferred elements remain valid, but now refer into *this, not into source.

Example:

map<std::string, int> m1;
m1["k1"] = 1;
m1["k2"] = 2;
m1["k3"] = 3;

map<std::string, int> m2;
m2["k1"] = 5;
m2["k3"] = 4;

m2.merge(m1);

for(const auto& p : m2) 
{ 
    std::cout << p.first << " -> " << p.second << "\n";
}

Will print:

k1 -> 5
k2 -> 2
k3 -> 4

live wandbox example


Here's a C++14 solution I came up with:

template <typename TMap0, typename TMap1>
auto merge(TMap0&& m0, TMap1&& m1)
{
    using map_type = std::remove_reference_t<TMap0>;

    // Move or copy `m0` into `result`.
    map_type result(std::forward<TMap0>(m0)); 

    // For each pair in `m1`...
    for(auto&& p : m1)
    {
        // If `m0` contains the key `p.first`...
        if(m0.count(p.first) != 0)
        {
            // Move or copy `p.second` into `result`.
            result[p.first] = forward_like<TMap1>(p.second);
        }
    }

    return result;
}

(forward_like can be found here.)

Example:

map<std::string, int> m1;
m1["k1"] = 1;
m1["k2"] = 2;
m1["k3"] = 3;

map<std::string, int> m2;
m2["k1"] = 5;
m2["k3"] = 4;

auto res = merge(m1, m2);
for(const auto& p : res) 
{ 
    std::cout << p.first << " -> " << p.second << "\n";
}

Will print:

k1 -> 5
k2 -> 2
k3 -> 4

live wandbox example

Upvotes: 3

Related Questions