C++ Intersect two maps on keys, keep value of first map - c++

I'm experiencing a problem with C++ and maps and intersection.
Have 3 maps, the first two being map<int, double>, and the last one being map<int, CustomType>.
I want to remove all instances of map keys from the first 2 maps, that do not exist as a key in the 3rd map. In brief, I have the third map that contains a list of objects, and the first two maps that contain some data about the objects. At some point in time the map with the objects is cleaned up and some items removed (user interaction) and now want to clean up the other two maps respectively.
I've tried the following:
map<int, double> map1, map2;
map<int, CustomType> map3;
for (auto it = map1.cbegin(); it != map1.cend(); )
{
if ( map3.find(it->first) == map3.end() )
{
map2.erase(it);
map1.erase(it++);
}
else ++it;
}
This gives me an error "pointer being freed was not allocated" on the map1.erase line. I've looked into set_intersection but I don't believe it would work in this case since the values will be different.
Any assistance is appreciated.

You need to iterate map1 and map2 independently. You cannot use an iterator of map1 to manipulate another map (to erase from map2 or to perform any other operations with map2).
So the code should be something like this:
map<int, double> map1, map2;
map<int, CustomType> map3;
for (auto it = map1.cbegin(); it != map1.cend(); )
{
if ( map3.find(it->first) == map3.end() )
it = map1.erase(it);
else
++it;
}
for (auto it = map2.cbegin(); it != map2.cend(); )
{
if ( map3.find(it->first) == map3.end() )
it = map2.erase(it);
else
++it;
}

You are trying to erase an element from map2 with an iterator from map1. That won't work. You need to get the key value from the iterator and use that to erase from map2. And when you called erase for map1 you invalidated your iterator, because you removed the element it was pointing to. Increment the iterator, then use the key value to call map1.erase().

You was close to the solution, but the problem is that an iterator is substantially a pointer.
So you can use "it" to remove both on map1 and map2.
void removeUnexist(const map<int, double>& m, const map<int, CustomType>::iterator& it) {
i = m.find(it->first);
if(i == m.end()) {
m.erase(i);
}
}
map<int, double> map1, map2;
map<int, CustomType> map3;
for (auto it = map3.cbegin(); it != map3.cend(); it++) {
removeUnexist(map1, it);
removeUnexist(map2, it);
}

Related

How can I access the values of a map as a whole

I have a map in c++ like this:
std::map<int, int> points;
I know that I can access the two integers for example in a for loop like this
for (auto map_cntr = points.begin(); map_cntr != points.end(); ++map_cntr)
{
int A = map_cntr->first; // key
int B = map_cntr->second; // val
}
But I want to know how I can access every point as a whole (and not it's entries like above).
I thought something like this:
for (auto map_cntr = points.begin(); map_cntr != points.end(); ++map_cntr)
{
auto whole_point = points.at(map_cntr);
}
Actually, I want to do operations on integers of a entry (point) of the map with integers of the following entry (point) of the map.
I want to do operations on integers of a entry (point) of the map
with integers of the following entry (point) of the map.
Map is not suited container to perform operation depending on the sequence of elements where you want to modify current element according to previous ones. For those things you can use a vector or an array of pairs for instance.
You can use foreach loop
std::map<int, int> points;
for (auto pair : points)
{
// pair - is what you need
pair.second;
pair.first;
auto whole_point = pair;
}
I want to do operations on integers of a entry (point) of the map with integers of the following entry (point) of the map
You can't directly modify the key of a [key,value] pair in a map. If you need to do so, you have to erase the pair and insert another one.
If you only need to write the value of a pair, or if you only need to read the pairs, you can do it with a single iterator, like this:
// assuming the map contains at least 1 element.
auto it = points.begin();
std::pair<const int, int>* currentPoint = &(*it);
it++;
for (; it != points.end(); ++it) {
auto& nextPoint = *it;
// Read-only: currentPoint->first, nextPoint.first
// Read/write: currentPoint->second, nextPoint.second
currentPoint = &nextPoint;
}
Live example

Erase nested map elements

I have a map which looks like
typedef std::map<int, std::set<float>> innerMap;
typedef std::map<long, innerMap> outerMap;
I want to do following:
1. I want to erase inner map elements for a key of outer map.
2. Then I want to erase outer map key if it contains 0 inner map elements.
For first scenario, I have written code as:
outerMap mapA;
//assuming this map contain an element
//longx is key in outer element, intx is key of inner element
std::map<int, std::set<float>>::const_iterator innerIter = mapA[longx].begin();
while (innerIter != mapA[longx].end())
{
if (innerIter->first == intx)
{
if (innerIter->second.size() == 0)
{
mapA[longx].erase(innerIter++);
}
break;
}
++innerIter;
}
I have written this code in C++ but I wanna use C++11. Can we write this in a better way in C++11?
For second scenario, do I need to iterate again outer map and check its value elements or I can do it in existing code itself?
This code looks way too complicated to me. The following should do the same, no need to use fancy C++11 features:
outerMap mapA;
// Lookup iterator for element of outerMap.
outerMap::iterator const outerIter = mapA.find(longx);
// Lookup iterator for element of innerMap that should be checked.
innerMap::const_iterator const innerIter = outerIter->second.find(intx);
// Check if element of innerMap should be erased and erase it if yes.
if(innerIter != outerIter->second.end() && innerIter->second.size() == 0) {
outerIter->second.erase(innerIter);
}
// Erase element of outer map is inner map is now empty:
// This should do scenario 2
if(outerIter->second.size() == 0) {
mapA.erase(outerIter);
}
what you do currently (in C++11):
auto& inner = mapA[longx];
const auto it = inner.find(intx);
if (it != inner.end() && it->second.size() == 0) {
inner.erase(it);
}

Is there a .at() equivalent for a multimap?

Is there any way to get an iterator to a multimap, for specific keys? For example:
multimap<string,int> tmp;
tmp.insert(pair<string,int>("Yes", 1));
tmp.insert(pair<string,int>("Yes", 3));
tmp.insert(pair<string,int>("No", 5));
tmp.insert(pair<string,int>("Maybe", 1));
tmp.insert(pair<string,int>("Yes", 2));
multimap<string,int>::iterator it = tmp.at("Yes);
Then I could use it for the work I want to do. Is this possible in C++? Or do we have to just cycle through the multimap, element by element, and check for the key before doing the work?
You have find for a single key value pair (any matching the key), or equal_range to get all of the pairs that match a given key (this seems to be your best bet.)
multimap<Key, T> only sort elements by its Key, so we can only find all the elements whose key value equals "Yes", then check each element one by one.
typedef multimap<string,int>::iterator Iterator;
pair<Iterator, Iterator> iter_range = tmp.equal_range("Yes");
Iterator it;
for (it = iter_range.first; it != iter_range.second; ++it) {
if (it->second == 3) {
break;
}
}
if (it != tmp.end()) {
tmp.erase(it);
}
In fact it's better to use multiset<T> in this case:
multiset< pair<string, int> > temp;
temp.insert(make_pair("Yes", 1));
temp.insert(make_pair("Yes", 3));
multiset< pair<string, int> >::iterator iter = temp.find(make_pair("Yes", 1));
if (iter != temp.end()) {
temp.erase(iter); // it erase at most one element
}
temp.erase(make_pair("Yes", 3)); // it deletes all the elements that equal to make_pair("Yes", 3)

How to check if my iterator stands on nothing

i'm using a multimap stl, i iterate my map and i did'nt find the object i wanted inside the map, now i want to check if my iterator holds the thing i wanted or not and i'm having difficulties with it because it's not null or something. thanx!
If it doesn't find the thing you want then it should equal the iterator returned by the end() method of the container.
So:
iterator it = container.find(something);
if (it == container.end())
{
//not found
return;
}
//else found
Why are you iterating over your map to find something, you should go like ChrisW to find a key in your map...
Mmm, are you trying to find the value in your map and not the key? Then you should do:
map<int, string> myMap;
myMap[1] = "one"; myMap[2] = "two"; // etc.
// Now let's search for the "two" value
map<int, string>::iterator it;
for( it = myMap.begin(); it != myMap.end(); ++ it ) {
if ( it->second == "two" ) {
// we found it, it's over!!! (you could also deal with the founded value here)
break;
}
}
// now we test if we found it
if ( it != myMap.end() ) {
// you also could put some code to deal with the value you founded here,
// the value is in "it->second" and the key is in "it->first"
}

STL Multimap Remove/Erase Values

I have STL Multimap, I want to remove entries from the map which has specific value , I do not want to remove entire key, as that key may be mapping to other values which are required.
any help please.
If I understand correctly these values can appear under any key. If that is the case you'll have to iterate over your multimap and erase specific values.
typedef std::multimap<std::string, int> Multimap;
Multimap data;
for (Multimap::iterator iter = data.begin(); iter != data.end();)
{
// you have to do this because iterators are invalidated
Multimap::iterator erase_iter = iter++;
// removes all even values
if (erase_iter->second % 2 == 0)
data.erase(erase_iter);
}
Since C++11, std::multimap::erase returns an iterator following the last removed element.
So you can rewrite Nikola's answer slightly more cleanly without needing to introduce the local erase_iter variable:
typedef std::multimap<std::string, int> Multimap;
Multimap data;
for (Multimap::iterator iter = data.begin(); iter != data.end();)
{
// removes all even values
if (iter->second % 2 == 0)
iter = data.erase(iter);
else
++iter;
}
(See also answer to this question)