Как я могу объединить две карты STL?
Как я могу объединить две карты STL в одну? Они оба имеют одинаковые ключи и типы значений (map<string, string>
). Если есть совпадение клавиш, я бы хотел отдать предпочтение одной из карт.
Ответы
Ответ 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>
.
Код на Колиру