2017-02-21 28 views
0

Мне нужно заменить несколько значений внутри STL map, но я не нашел ничего полезного в <algorithm>.Заменить несколько элементов на карте STL

псевдокод:

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; 

Метод merge должен заменить m1 значения с m2 значениями, когда ключи матча.

Я прочитал документацию merge, но мне кажется, что ее нельзя использовать с картами.

+1

'зЬй :: копию (m1.begin(), m1.end(), std :: inserter (m2, m2.begin())); 'будет вставлять в' m2' элементы, которые существуют и имеют различное значение в 'm1', я думаю, что результат тот же –

+0

@Piotr: ваше решение добавляет в 'm2' пару k2/v2. Я попытался поменять 'm1' и' m2' внутри 'copy', но это не сработает. –

+0

* "будет вставляться в м2 элементов, которые существуют и имеют разное значение в m1" * –

ответ

3

C++ 17 добавляет std::map::merge, который делает то, что вы хотите:

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

Попытки извлечь ("сращивание") каждый элемент в источнике и вставить его в * это с помощью сравнения объект * этого. Если в элементе есть элемент * с ключом, эквивалентным ключу элемента из исходного кода, то этот элемент не извлекается из источника. Никакие элементы не копируются и не перемещаются, только внутренние указатели узлов контейнера повторно назначаются. Все указатели и ссылки на переданные элементы остаются в силе, но теперь относятся к * этому, а не к источнику.

Пример:

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

Напечатает:

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

live wandbox example


Вот раствор C++ 14 я придумал:

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.)

Пример:

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

Напечатает:

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

live wandbox example

+0

Спасибо за четкое объяснение! Короткий ответ: если вы не используете C++ 17, вам нужно написать собственный алгоритм цикла и проверки. Я прав? –

+0

Добро пожаловать. «Loop-and-check» - одно из возможных решений. Вероятно, существуют разные решения, которые либо используют '', либо используют разные стратегии. –