Как я могу объединить две карты 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>.

Код на Колиру