boost unordered_multimap loop over the unique keys - c++

What is the easiest way to loop over the unique keys in a boost unordered_multimap.
For example I have this:
std::set<int> used;
for (auto p : valuesMap)
{
if (used.count(p.first))
continue;
used.insert(p.first);
auto range = valuesMap.equal_range(p.first);
if (p.first)
for (auto v = range.first; v != range.second; ++v)
//do something;
}
Is there better way to do that. It seems like the unique keys should be already known to the unordered map.

What you want to do is find a way to get the iterator following a certain key. In multimap I'd usually use upper_bound. But since unordered_multimap doesn't have that - I'll have to use equal_range.second:
for (auto iter=valueMap.begin();
iter!=valueMap.end();
iter=ValueMap.equal_range(iter->first)->second){
uniq_key=iter->first;
// Do whatever you want with uniq_key
}
But your example is weird to me - because you DO go over all the element . If I wanted to write your code, doing what you do, this is how I'd do it:
for (auto iter=valueMap.begin()
iter!=valueMap.end();
){ // Notice the lack of ++iter!!!
auto end=valueMap.equal_range(ier->first)->second;
for (;iter!=end;++iter)
// Do something
}

Related

Retrieve first key of std::multimap, c++

I want to retrieve just the first key of a multimap. I already achieved it with iterating through the multimap, taking the first key and then do break. But there should be a better way, but I do not find it.
int store_key;
std::multimap<int, int> example_map; // then something in it..
for (auto key : example_map)
{
store_key = key;
break;
}
This solves the Problem, but I am searching for another solution.
Your range based for loop is more or less (not exactly but good enough for this answer) equivalent to:
for (auto it = example_map.begin(); it != example_map.end(); ++it) {
auto key = *it;
store_key = key;
break;
}
I hope now it is clear that you can get rid of the loop and for a non-empty map it is just:
auto store_key = *example_map.begin();
Note that store_key is a misnomer, because it is not just the key and your code would trigger a compiler error. It is a std::pair<const int,int>. store_key->first is the key.

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

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

Combining multiple maps with vectors into one map

I have a question about combining maps that have vectors as the value section. for instance, I might have the following:
std::map<int, std::vector<Affector*> > affectors;
I want to build this map by combining multiple smaller maps. For instance:
for (auto ch = chList.begin(); ch != chList.end(); ++ch)
{
std::map<int, std::vector<Affector*> > tempAff = ch->getemng()->getAffectorsInOrder();
std::map<int, std::vector<Affector*> > tempAff2 = ch->getpmng()->getAffectorsInOrder()
//I want to append both of these maps to the top level affectors map
}
I can think of the obvious solution which would be
for (auto ch = chList.begin(); ch != chList.end(); ++ch)
{
std::map<int, std::vector<Affector*> > tempAff = ch->getemng()->getAffectorsInOrder();
for (auto aff = tempAff.begin(); aff != tempAff.end(); ++aff)
{
affectors[aff->first].push_back(aff->second);
}
tempAff.clear();
tempAff = ch->getpmng()->getAffectorsInOrder();
for (auto aff = tempAff.begin(); aff != tempAff.end(); ++aff)
{
affectors[aff->first].push_back(aff->second);
}
...
}
This will work, but feels inefficient. I can't use the insertion operation of the map since I need to preserve existing values in the vectors. Is there a better way to combine the maps I'm not thinking of?
Thanks
As mentioned by Richard Corden I think that you really want to be using a std::multimap.
std::multimap<int, Affector*> affectors;
If you also make tempAff and tempAff2 std::multimaps you can do:
affectors.insert(tempAff.begin(), tempAff.end());
affectors.insert(tempAff2.begin(), tempAff2.end());

std::multimap getting two ranges

I'm using a C++ std::multimap and I have to loop over two different keys. Is there an efficient way to do this other than creating two ranges and looping over those ranges seperately?
This is the way im doing it now:
std::pair<std::multimap<String, Object*>::iterator,std::multimap<String, Object*>::iterator> range;
std::pair<std::multimap<String, Object*>::iterator,std::multimap<String, Object*>::iterator> range2;
// get the range of String key
range = multimap.equal_range(key1);
range2 = multimap.equal_range(key2);
for (std::multimap<String, Object*>::iterator it = range.first; it != range.second; ++it)
{
...
}
for (std::multimap<String, Object*>::iterator it2 = range2.first; it2 != range2.second; ++it2)
{
...
}
The code you started with is the most straightforward.
If you'd really like to iterate over two ranges in the same loop, you can create a custom iterator that takes two iterator ranges, iterates over the first until it's done then switches to the second. This is probably more trouble than it's worth, as you'd need to implement all of the iterator members yourself.
Edit: I was overthinking this; it's easy just to modify the two loops into a single one.
for (std::multimap<String, Object*>::iterator it = range.first; it != range2.second; ++it)
{
if (it == range.second)
{
it = range2.first;
if (it == range2.second)
break;
}
...
}
Boost does this, of course. Using Boost.Range and its join function will get you what you want. See Boost Range Library: Traversing Two Ranges Sequentially for more details.
If you have access to C++-11 (Visual Studio 10+, gcc-4.5+) and are allowed to use it auto is a real gem:
// get the range of String key
auto range = multimap.equal_range(key1);
auto range2 = multimap.equal_range(key2);
for (auto it = range.first; it != range.second; ++it)
{
...
}
for (auto it2 = range2.first; it2 != range2.second; ++it2)
{
...
}
Anyway, I would just test the keys and only do the second loop if key2 != key1. Checking iterators each time in a loop has some cost.
A std::set_difference of the first range from the second might streamline the code.
Maybe std::set_union the two ranges and insert through back_inserter into a set so you only get one copy?
Some experiments may be in order. Don't forget to put your first guess in the mix. It might surprise you by being just fine in terms of speed. Unless the ranges are typically very long and/or the loop operation is expensive it may not be worth the headache of extra bookkeeping.