Comment fusionner deux cartes STL en une seule? Ils ont tous deux les mêmes types de clé et de valeur (map<string, string>
). S'il y a un chevauchement des touches, je voudrais donner la préférence à l'une des cartes.
En supposant que vous souhaitiez conserver les éléments dans mapA
et fusionner les éléments dans mapB
pour lesquels il n'y a pas de clé dans mapA
:
mapA.insert(mapB.begin(), mapB.end())
fera ce que vous voulez, je pense.
Exemple de travail:
#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;
}
sortie:
:!./insert
1:11 2:12 3:13
2:20 3:30 4:40
1:11 2:12 3:13 4:40
Si vous souhaitez copier des entrées d'une mappe vers une autre, vous pouvez utiliser std::map
's insert
:
targetMap.insert(sourceMap.begin(), sourceMap.end());
Mais notez que insert
ne met pas à jour les éléments si leur clé est déjà dans targetMap; ces éléments seront laissés tels quels. Pour écraser des éléments, vous devrez copier explicitement, par exemple:
for(auto& it : sourceMap)
{
targetMap[it.first] = it.second;
}
Si cela ne vous dérange pas de perdre les données dans sourceMap
, une autre façon de réaliser un copier-écraser est de insert
la cible dans la source et std::swap
Les resultats:
sourceMap.insert(targetMap.begin(), targetMap.end());
std::swap(sourceMap, targetMap);
Après l'échange, sourceMap
contiendra les anciennes données de targetMap
et targetMap
sera une fusion des deux cartes, avec une préférence pour les entrées de sourceMap
.
Notez que, depuis C++ 17, il existe une méthode merge()
pour les cartes.
Selon ISO/CEI 14882: 2003, section 23.1.2, tableau 69, expression a. Insérer (i, j):
pre: i, j ne sont pas des itérateurs dans a. insère chaque élément de la plage [i, j) si et seulement s'il n'y a pas d'élément avec une clé équivalente à la clé de cet élément dans des conteneurs avec des clés uniques;
Étant donné que std :: map doit suivre cette restriction, si vous souhaitez donner la préférence aux "valeurs" d'une carte par rapport à une autre, vous devez l'insérer. Par exemple,
std::map<int, int> goodKeys;
std::map<int, int> betterKeys;
betterKeys.insert(goodKeys.begin(), goodKeys.end());
Donc, s'il y a des clés équivalentes dans goodKeys et betterKeys, les "valeurs" des betterKeys seront préservées.
Comme mentionné dans réponse de John Perry , puisque C++ 17std::map
fournit un merge()
fonction membre. La fonction merge()
produit le même résultat pour la carte cible que solution de jkerian basé sur l'utilisation de insert()
, comme vous pouvez le voir sur l'exemple suivant, que j'ai emprunté à jkerian. Je viens de mettre à jour le code avec certaines fonctionnalités C++ 11 et C++ 17 (telles que using
alias de type , basé sur la plage) pour la boucle avec liaison structurée , et initialisation de la liste ):
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;
}
Sortie:
1:11 2:12 3:13
2:20 3:30 4:40
1:11 2:12 3:13 4:40
Comme vous pouvez le voir, merge()
donne également la priorité à la carte cible foo
lorsque les touches se chevauchent. Si vous voulez l'avoir dans l'autre sens, alors vous devez appeler bar.merge(foo);
.
Cependant, il existe une différence entre l'utilisation de insert()
et merge()
concernant ce qui arrive à la carte source. Les fonctions insert()
ajoutent de nouvelles entrées à la carte cible, tandis que merge()
déplace les entrées de la carte source. Cela signifie que pour l'exemple ci-dessus, insert()
ne modifie pas bar
, mais merge()
supprime 4:40
De bar
, de sorte que seuls 2:20
et 3:30
restent dans bar
.
Remarque: J'ai réutilisé l'exemple de jkerian qui utilise map<int, int>
Par souci de concision, mais merge()
fonctionne également pour votre map<string, string>
.