Retrieve first key of std::multimap, c++ - 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.

Related

Get the previous or next item in a map from a for loop

I'm making a calculator that can accept more than one operator at once (e.g. 5x5x5). I have a map that contains the positions of the operators, and what type they are (x/+-). I also have a for loop for (auto const& [key, val] : oper_map) which I got from this post.
In order to get the left and right numbers, I need to know where the left and right operators are. I've attempted to use std::prev and std::next with the key like this:
int loper_pos = -1;
int roper_pos = 0;
double lnum;
double rnum;
char loper;
char roper;
//map defined elsewhere
for (auto const& [key, val] : oper_map)
{
//loper is left operator while roper is right opeprator
//tracks the position of the loop
int map_pos = std::distance(oper_map.begin(), oper_map.find(key));
if (map_pos == 0) loper_pos = -1;
else
{
loper_pos = std::prev(key);
loper = std::prev(val);
}
if (map_pos == oper_map.size()) roper_pos = oper_map.size() + 1;
else
{
roper_pos = std::next(key);
roper = std::next(val);
}
but I guess it doesn't work since key isn't an iterator? I also can't increment/decrement key or val (or when using the C++11 version in this post), so I guess it doesn't count as an iterator? I don't know iterators confuse me.
This post appears to be what I want but for whatever reason lower_bound() does not work with oper_map; no suitable conversion.
No. key is not an iterator.
for (auto const& [key, val] : oper_map)
key is a const reference to the key in the map. If you want iterators, use iterators:
for (auto it = oper_map.begin(); it != oper_map.end(); ++it) {
auto next = std::next(it);
auto prev = std::prev(it);
}
However, consider that std::map is not a sequential container. If you are interested in the positions of elements in the container, maybe a std::vector< std::pair<Key,MappedValue>> is more handy.

How can I code a loop that compares every element of an unordered_set with all the others, using iterators in C++?

I have an unordered_set and I need to pick each element and compare it with all the others.
Notes:
If A and B are compared, I don't need to compare B and A.
My unordered_set is the value of an unordered_map, for which the key is a pair.
I tried the following:
unordered_map <pair<int, int>, unordered_set <int>, boost::hash<std::pair<int,int>>> gridMap;
unordered_map <int, rigidBody*> objectsMap;
auto gridMapIt = gridMap.begin();
while (gridMapIt != gridMap.end()) // loop the whole gridMap
{
auto setItOut = gridMapIt->second.begin();
while (setItOut != gridMapIt->second.end()) // loop each element of the set
{
auto setItIn = gridMapIt->second.begin();
while (setItIn != gridMapIt->second.end()) // versus each other element
{
//compare and do stuff
++setItIn;
}
checked.insert({ objectsMap[*setItOut]->getID(), objectsMap[*setItIn]->getID() });
checked.insert({ objectsMap[*setItIn]->getID(), objectsMap[*setItOut]->getID() });
++setItOut;
}
++gridMapIt;
}
The error I am getting is "Expression: cannot dereference end list iterator". If I remove or comment the innermost while loop, it works fine.
Thanks in advance.
The use of *setItIn after the loop is invalid. At that point you have an iterator that points past the last element. That's what the error is telling you.
If you change from while to for you can use the scoping rules to stop yourself from dereferencing invalid iterators.
Rather than populate checked, you can start the inner loop from the next element, rather than the first.
for (auto & gridElem : gridMap) {
for (auto setItOut = gridElem.second.begin(), setEnd = gridElem.second.end(); setItOut != setEnd; ++setItOut) {
for (auto setItIn = std::next(setItOut); setItIn != setEnd; ++setItIn) {
//compare and do stuff
}
// setItIn not visible here
}
}

boost unordered_multimap loop over the unique keys

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
}

How to iterate through map, modify map but restore at each iteration?

I have a std::map<int,int> lets call it my_map
I iterate through this map using iterators and a for loop.
Within each iteration I want to modify many elements in this map but restore it again to its original values for next iteration of the loop.
I thought I could create a temporary copy of the iterator my_temp_map , but then I wouldn't be able to use the iterator to find the element I ought to be working on.
I then thought I could create a temporary copy, work on the origin my_map and at the end of each loop restore the original back to the temporary copy. However I believe this would invalidate the iterators as an assignment deletes all elements
How does one solve this problem?
Code added
So each inner loop will modify current_partition (and there is some more absent code that will store the result of the modified current_partition), but after each inner_loop I need current_loop to be restored to its former self.
std::map<int,int> current_partition = bitset_to_map(centre->second->bit_partitions);
int num_parts = (std::max_element(current_partition.begin(), current_partition.end(),value_comparer))->second;
for (std::map<int,int>::iterator itr = current_partition.begin(); itr != current_partition.end(); ++itr) {
for (int next_part = 0; next_part<num_parts+1; ++next_part) {
if (next_part != itr->second) {
int current_part = itr->second;
itr->second = next_part;
std::vector<int> first_changed_part, last_changed_part;
for (std::map<int,int>::iterator new_itr = current_partition.begin(); new_itr != current_partition.end(); ++new_itr) {
if (new_itr->second == current_part)
first_changed_part.push_back(new_itr->first);
if (new_itr->second == next_part)
last_changed_part.push_back(new_itr->first);
}
}
}
}
I think that std::advance may be of help. Create the temp, then advance begin() until you're where you are now (found out with std::distance)...then whatever it is you're trying to do.
With the code, I understand what you're going for now. I'd do it pretty much the first way you suggest: each time through the outer loop, make a temporary copy of the current_partition data structure, and then work on that, discarding it at the end.
You said that the problem with that would be that you couldn't use an iterator into the original map to find the element you ought to be working on. That's true; you can't do that directly. But it's a map. The element you're working on will have a key which will be the same in any copy of the data structure, so you can use that to create an iterator to the element that you ought to be working on in the copy.
For instance:
std::map<int,int> current_partition = bitset_to_map(centre->second->bit_partitions);
int num_parts = (std::max_element(current_partition.begin(), current_partition.end(),value_comparer))->second;
for (std::map<int,int>::iterator itr = current_partition.begin(); itr != current_partition.end(); ++itr) {
// Make a temporary copy of the map. Iterators between the original and the copy aren't
// interchangeable, but the keys are.
std::map<int,int> tmp_current_partition = current_partition;
// Use the iterator itr to get the key for the element you're working on (itr->first),
// and then use that key to get an equivalent iterator into the temporary map using find()
std::map<int,int>::iterator tmp_itr = tmp_current_partition.find(itr->first);
// Then just replace current_partition with tmp_current_partition and
// itr with tmp_itr in the remainder (hopefully I didn't miss any)
for (int next_part = 0; next_part<num_parts+1; ++next_part) {
if (next_part != tmp_itr->second) {
int current_part = tmp_itr->second;
tmp_itr->second = next_part;
std::vector<int> first_changed_part, last_changed_part;
for (std::map<int,int>::iterator new_itr = tmp_current_partition.begin(); new_itr != tmp_current_partition.end(); ++new_itr) {
if (new_itr->second == current_part)
first_changed_part.push_back(new_itr->first);
if (new_itr->second == next_part)
last_changed_part.push_back(new_itr->first);
}
}
}
}

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