sociales pueblo observatorio los informe defensoría conflictos clasifica c++ merge stdmap

c++ - observatorio - la defensoría del pueblo clasifica los conflictos sociales en



¿Cómo fusiono dos mapas en STL y aplico una función para conflictos? (3)

He leído la pregunta de Combinar dos mapas STL y, aunque está cerca, estaba buscando una funcionalidad como la que se describe here .

En resumen, me gustaría unir dos instancias std::map (que tienen la misma clave y tipo de valor) en una, con la advertencia de que me gustaría agregar los valores si el objeto existe en ambos mapas.

¿Existe una función boost , range-v3 o std que pueda hacer esto? Y si no, ¿cuál sería la mejor manera de lograrlo?

Código de ejemplo:

double mergePredicate(double lhs, double rhs) { return lhs + rhs; } int main() { std::map<int, double> mapA = { {0, 1.0}, {1, 2.0} }; std::map<int, double> mapB = { {1, 1.5}, {2, 2.5} }; // Merge maps in some way... merge(mapA, mapB, mergePredicate); // result: mapA == { {0, 1.0}, {1, 3.5}, {2, 2.5} } for (const auto& p : mapA) { std::cout << p.first << " " << p.second << std::endl; } }


No conozco ninguna función existente para eso, pero puede rodar la suya desde algo similar a la implementación std::merge para tener una complejidad lineal:

template<class Map, class Merger> void merge(Map& dest, const Map& source, Merger merger) { auto it1 = dest.begin(); auto it2 = source.begin(); auto&& comp = dest.value_comp(); for (; it1 != dest.end() && it2 != source.end(); ) { if (comp(*it1, *it2)) { ++it1; } else if (comp(*it2, *it1)) { dest.insert(it1, *it2); // with hint to have correct complexity ++it2; } else { // equivalent it1->second = merger(it1->second, it2->second); ++it1; ++it2; } } dest.insert(it2, source.end()); }

Demo


No conozco ninguna función existente para hacer esto, pero puedes usar la función de merge de std::map ( ejemplo en vivo ):

template<typename K, typename V, typename F> void mergeWithConflicts(std::map<K, V>& base, std::map<K, V> toMerge, F combine) { base.merge(toMerge); // All that''s left in toMerge is conflicting keys for (const auto& [k, v] : toMerge) { base[k] = combine(base[k], toMerge[k]); } }

Como beneficio adicional, la implementación de la merge es bastante eficiente en comparación con lo que puede hacer a mano, a menos que la vuelva a implementar utilizando extract . En lugar de copiar o mover elementos, ajusta los punteros internos para mover los nodos de un mapa a otro. Sin embargo, esto significa que modifica el otro mapa. Como se sugirió, el parámetro se toma por valor, por lo que el otro mapa se puede mover si ya no es necesario y se puede copiar de otra manera.


Para este caso específico, debido a que el operator[] crea una clave si no existe, puede usar un ciclo simple para agregar los dos valores:

for (const auto& pair : mapB) { mapA[pair.first] += pair.second; }

Y cuando quiera usar una función, pero está bien usar un valor inicializado por defecto donde no exista una clave:

for (const auto& pair : mapB) { mapA[pair.first] = mergePredicate(mapA[pair.first], pair.second); }