ti-enxame.com

Como mesclar dois mapas STL?

Como mesclar dois mapas STL em um? Ambos têm os mesmos tipos de chave e valor (map<string, string>). Se houver uma sobreposição de chaves, gostaria de dar preferência a um dos mapas.

61
JonF

Supondo que você queira preservar os elementos em mapA e mesclar elementos em mapB para os quais não há chave em mapA:

mapA.insert(mapB.begin(), mapB.end())

vai fazer o que você quiser, eu acho.

Exemplo de trabalho:

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

saída:

:!./insert
1:11 2:12 3:13
2:20 3:30 4:40
1:11 2:12 3:13 4:40
113
jkerian

Se você deseja copiar entradas de um mapa para outro, pode usar std::map _ insert:

targetMap.insert(sourceMap.begin(), sourceMap.end());

Mas observe que insert não atualiza elementos se sua chave já estiver no targetMap; esses itens serão deixados como estão. Para substituir elementos, você precisará copiar explicitamente, por exemplo:

for(auto& it : sourceMap)
{
    targetMap[it.first] = it.second;
}

Se você não se importa em perder os dados em sourceMap, outra maneira de obter uma cópia e substituição é insert o destino na origem e std::swap os resultados:

sourceMap.insert(targetMap.begin(), targetMap.end());
std::swap(sourceMap, targetMap);

Após a troca, sourceMap conterá os dados antigos de targetMap e targetMap será uma mesclagem dos dois mapas, com preferência pelas entradas de sourceMap.

29
kiwibonga

Observe que, desde o C++ 17, existe um método merge() para mapas.

11
John Perry

De acordo com a ISO/IEC 14882: 2003, seção 23.1.2, Tabela 69, expressão a.insert (i, j):

pre: i, j não são iteradores em a. insere cada elemento do intervalo [i, j) se e somente se não houver elemento com chave equivalente à chave desse elemento em contêineres com chaves exclusivas;

Como esse std :: map deve seguir esta restrição, se você deseja dar preferência a "valores" de um mapa em detrimento de outro, insira nele. Por exemplo,

std::map<int, int> goodKeys;
std::map<int, int> betterKeys;

betterKeys.insert(goodKeys.begin(), goodKeys.end());

Portanto, se houver chaves equivalentes em goodKeys e betterKeys, os "valores" das betterKeys serão preservados.

3
Valentine Savchenko

C++ 17

Conforme mencionado em resposta de John Perry , uma vez que C++ 17std::map fornece uma merge() função de membro. A função merge() produz o mesmo resultado para o mapa de destino que solução de jkerian com base no uso de insert() , como você pode ver em o exemplo a seguir, que peguei emprestado do jkerian. Acabei de atualizar o código com alguns recursos C++ 11 e C++ 17 (como using alias do tipo) , com base no intervalo para loop com ligação estruturada e inicialização da lista ):

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

Saída:

1:11 2:12 3:13
2:20 3:30 4:40
1:11 2:12 3:13 4:40

Como você pode ver, merge() também dá prioridade ao mapa de destino foo quando as teclas se sobrepõem. Se você quiser fazer o contrário, precisará chamar bar.merge(foo);.

No entanto, há uma diferença entre usar insert() e merge() em relação ao que acontece com o mapa de origem. As funções insert() adicionam novas entradas ao mapa de destino, enquanto merge() move as entradas do mapa de origem. Isso significa para o exemplo acima, que insert() não altera bar, mas merge() remove 4:40 De bar, para que apenas 2:20 e 3:30 permanecem em bar.

Nota: Eu reutilizei o exemplo do jkerian que usa map<int, int> Por uma questão de brevidade, mas merge() também funciona para o seu map<string, string>.

Código em Colir

1
honk