compare keys in map against a function - c++

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.

Related

How can we iterate Map link linear structure even though they are implemented as red black or AVL tree?

How can we iterating over the map as if it was a linear data structure and also tell me how we simply put in the key to get the value associated.?
You should use iterators to iterate over the map:
std::map<int, int> myMap;
for (auto iter = myMap.begin(); iter != myMap.end(); ++iter)
// do something with iter
or you can use the loop syntax:
for (auto& myMapPair : myMap)
// do something with the pair
Note that for the first version you can access the key with iter->firstand the value with iter->secondas iter is an iterator to a pair. For the second version you directly have a reference to a pair so you should use iter.first and iter.second.
As for finding the value from a key you should do:
auto iter = myMap.find(50);
if (iter == myMap.end()) // didn't find anything
// do something
else // you found something
// do something

Starting a map iterator not at city.begin()

In short, when trying to iterate through a map, is it possible to start the iterator at an index/key that isn't *.begin()?
I have a map of cities with a class "City". (City has coordinates for the city, and in the following code, calc_dist(c1, c2) will calculate the distance between the coordinates). What I am trying to do is create a "2D Map" (i.e. map<string, map<string, double>> dist) that can access the distance between the city by using dist[city1][city2].
to compute the distances I basically create a nested iterator over the cities, and it works, but it's slow when using many cities. since the distance between cities are symmetric, i can cut the loops in half by storing the distance in the reverse of the map.
what i was hoping to do was start the second iterator at the current city from the first iterator. http://www.cplusplus.com/reference/map/map/ tells me that the order is preserved so I feel like I should be able to do this.
Sample code:
// Function create_distance_chart(...)
map<string, map<string, double>> create_distance_chart(map<string, City> c){
map<string, map<string, double>> dist;
for (map<string, City>::iterator it = c.begin(); it != c.end(); ++it){
for (map<string, City>::iterator it2 = c.begin(); it2 != c.end(); ++it2) { // here i can make improvements, i hope
//calculate distance
dist[c[it->first]][c[it2->first]] = calc_dist(c[it->first],c[it2->first])// store in map
dist[c[it2->first]][c[it->first]] = calc_dist(c[it->first],c[it2->first])// store in map in the other direction.
}
}
}
in the line
for (map<string, City>::iterator it2 = c.begin(); it2 != c.end(); ++it2) {
i tried to change c.begin to c[it->first], c.at(it->first), just it->first, and a dummy variable that pulls the index for it->first.
the only other method i'm considering is doing a reverse iterator for the second iterator and having a termination condition that might cause the second loop to end before it2 != c.end() (i.e. at the first iterator's city), but i'm not making headway in that domain right now.
Thanks in advance!
First of all this statment:
c[it->first]
is a slow and convoluted way to simply say:
it->second
and as you use that 8 times in your loop there is no surprise it is slow indeed.
And for your loop, looks like you want to change second loop to:
for (map<string, City>::iterator it2 = std::next(it); it2 != c.end(); ++it2)
Note: if you do not have intention to change values in the map it is cleaner to use std::map::const_iterator instead.
Note2: I assumed that calculating distance btw a city and itself is meaningless. If it is not the case in your geometry then remove std::next() in above code and just assign it to it2 in the second loop initialization.

Iterate up to and including position

Probably very simple but can't get my head around it atm
I have this
// standard std::map and std::map::iterator
auto pos = map.find(val);
for(auto it = map.begin; it != pos; ++it)
I want to search for an element and then process all elements before (container is ordered, so just in iteration order) and including the find location, however this doesn't appear to examine the final element at position 'pos'. How can I achieve this?
Just move things around.
auto pos = map.find(val);
for(auto it = map.begin(); it != map.end(); ++it)
{
// Do something
if (it == pos)
break;
}
If it's possible that the value does not exist in the map, this will simply end up iterating over the entire map and that's why it != map.end(); is explicitly needed, to catch this particular runaway train...
Caution: if you have explicit continues inside the for loop, some additional TLC will be needed.
You need to differentiate between the cases where val is found in map and otherwise:
void f(/*map::[const_]iterator*/ it);
auto pos = map.find(val);
for (auto it = map.begin(); it != pos; ++it)
f(it);
if (pos != map.end())
f(pos);
You could use a do...while() loop but you would have to check for pos!=end() each time.

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)