Как я могу объединить две карты STL в одну? Они оба имеют одинаковые ключи и типы значений (map<string, string>). Если есть совпадение клавиш, я бы хотел отдать предпочтение одной из карт.
Как я могу объединить две карты STL?
Ответ 1
Предполагая, что вы хотите сохранить элементы в mapA и объединить элементы в mapB для которых нет ключа в mapA:
mapA.insert(mapB.begin(), mapB.end())
будет делать то, что вы хотите, я думаю.
Рабочий пример:
#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
Ответ 2
Если вы хотите скопировать записи с одной карты на другую, вы можете использовать std::map insert:
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 записей.
Ответ 3
Обратите внимание, что начиная с С++ 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 есть какие-то эквивалентные ключи, будут сохранены "значения" лучшихKeys.
Ответ 5
С++ 17
Как упоминалось в ответе Джона Перри, поскольку С++ 17 std::map предоставляет функцию-член merge(). Функция merge() выдает тот же результат для целевой карты, что и jkerian solution, на основе использования insert(), как вы можете видеть из следующего примера, который я позаимствовал у jkerian. Я только что обновил код, добавив некоторые функции С++ 11 и С++ 17 (например, псевдоним типа using, для цикла, с структурированная привязка и инициализация списка):
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() удаляет 4:40 из bar, так что только 2:20 и 3:30 остаются в bar.
Примечание: я повторно использовал пример из jkerian, в котором для краткости используется map<int, int>, но merge() также работает для вашего map<string, string>.