How to check if my iterator stands on nothing - c++

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

Related

unordered_map iterator points to end(), how can I retrieve a key from unordered_map?

I am currently trying to return the key value only from an unordered_map, groups, that has a string as a key and a vector of strings as my value. I am currently encountering the issue that my it iterator for the unordered_map, groups, is pointing at the end() and makes my statement false, never returning my groupKey. I can only use hasNext and getNextHome to iterate through my map. So for-loops cannot be used for this task.
I've initialized them as such in my header file:
Home::Home()
{
iter = 0;
it = groups.begin();
}
private:
int iter; // the iterator
unordered_map<string, vector<string>>::iterator it; // iterator for the map
void Home::resetHomeIterator()
{
iter = 0;
it = groups.begin();
}
bool Home::hasNext() {
if (iter == groups.size() && it == groups.end()) {
return false;
}
else if (iter < groups.size()) {
return true;
}
return false;
}
string Home::getNextHome()
{
if (hasNext() == false || it == groups.end()) {
resetHomeIterator();
}
it++;
string groupKey = it->first;
return groupKey;
}
Whenever I run this, the it->first gives me an error that I cannot "dereference end list iterator" and when I debug, I never get a groupKey back, it just goes to false so I never get a key returned.
I am trying to get a groupKey back and use a while-loop for my hasNext in my main.cpp file ( while (hasNext) ) and iterate the key values that way. I know my group map is not empty either, I saw as I was using the debugger that they were being placed accordingly. I've tried to work around it, but I'm not sure if I'm getting it. I might be missing something. How can I retrieve just the key since it's a string?
The main reason for this question is because iter is out of bounds. The element number of groups starts from 0. group.end() points to the position after the last valid element in the continuous space. So, iter should not become group.size().
if (iter == groups.size()-1 && it == groups.end()) {
return false;
}
In addition, it is not recommended to use iterators in Home. Because iterator and pointer are not the same. Iterators are for iterating and should be considered transient, and not stored for later use.

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

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

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

compare keys in map against a function

I have a map<int, string>. The keys refer to client nodes.
I need to traverse the map, and compare each key to every other key held within a map against a boolean function (which checks if the nodes are connected).
I.e. what is the best way to do something like
map<int, string> test_map;
map<int, string>::iterator iter;
for (iter = test_map.begin(); iter!=test_map.end(); iter++)
{
int curr_node = iter->first;
/* psuedo-code:
1. iterate through other keys
2. check against boolean e.g. bool fn1(curr_node, test_node) returns true if nodes are connected
3. perform fn2 if true */
}
I'm not sure how to do the iteration part with the other keys in the nodes - much thanks in advance.
The completely naive solution is this:
map<int, string>::iterator iter, iter2;
for ( iter = test_map.begin(); iter != test_map.end(); iter++)
{
int curr_node = iter->first;
for ( iter2 = test_map.begin(); iter2 != test_map.end(); iter2++)
{
if( iter == iter2 ) continue;
int test_node = iter2->first;
if( fn1(curr_node, test_node) ) fn2();
}
}
Taking a step back, perhaps you'd be better served by a slightly different data structure here?
An adjacency list or matrix might work better, at least for this task you're asking about.
The gist is that you'd have an edge-centric, not a node-centric, data structure. That would make your stated task of calling fn2 on every pair of connected nodes very easy.
Let me know if this approach makes sense given your requirements and I'll be happy to include more details or references.

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)