How to get pair from a map using key in C++ - c++

I have the following map:
std::map<char, std::pair<int, int> > robots;
I am using this function to populate the map given the input meets certain conditions:
bool World::addRobot(int row, int col, char robot_name) {
// This if block checks if the desired location is a valid 1 and keeps a track of all the robots already in the grid
if (map_[row][col] == '1' && robots.find(robot_name) == robots.end()){
map_[row][col] = robot_name;
robots.insert(make_pair(robot_name, std::make_pair(row, col)));
}
else{std::cout << "Invalid input" << std::endl;}
return true;
}
Each robot name, which is just a single char, is saved with a pair of its location, which are just row/col coordinates. In the following function, I want to be able to retrieve & ethe location pairs given the robot name:
std::pair<int, int> World::getRobot(char robot_name) {
std::pair<int, int> location = robots.find(robot_name);
return location;
}
But the name location is redlines with the following error message:
No viable conversion from 'std::map<char, std::pair<int, int>>::iterator' (aka '_Rb_tree_iterator<std::pair<const char, std::pair<int, int>>>') to 'std::pair<int, int>'
Where am I going wrong? How can I return the coordinate pairs from just the robot name?

An iterator for a map "points to" a std::pair<const KEY, VALUE>.
For your map, the KEY is char and the VALUE is std::pair<int, int>
So in your code, instead of:
std::pair<int, int> location = robots.find(robot_name);
you need to:
std::pair<int, int> location = robots.find(robot_name)->second;
Also, you need to check and see if the call to find fails to find the key you want. In that case the iterator will be equal to robots.end, and you'll have to deal with that:
const auto it = robots.find(robot_name);
if (it != robots.end()) {
return it->second;
} else {
// Not found, do something else
}

std::map::find returns a map iterator which is a "logical pointer" to a std::pair of key and value of the element in the map (not only the value).
The second member of this pair is the value that you seek to return from getRobot (which is by itself a pair of ints).
Fixed version:
std::pair<int, int> World::getRobot(char robot_name)
{
auto it = robots.find(robot_name);
if (it == robots.end())
{
return std::pair<int, int>(0, 0); // return some default value
}
return it->second;
}
2 additional notes:
I used auto which is very convenient when using iterators (instead of specifying the long iterator type).
I added a check whether the key is in the map. If not - return some default value. You can change the default value, or change the method prototype to return an error status in this case.

Related

Why is pair not working with unordered_map?

The following code doesn't compile.
The line with pair is giving the error. Is there some other way to access the data or is this
way correct??
unordered_map<int,int> hm;
unordered_map<int,int>::iterator it;
it=find(hm.begin(),hm.end(),x+c);
if (it!=hm.end())
{
bNotFound = false;
pair<int,int> p = *it;
ind = p.second;
}
Sometimes the compiler does a lousy job with the error messages. Your problem is the find algorithm.
unordered_map & map have their own find, which take the key as argument and returns an iterator. The algorithm is looking for the key:
auto it = hm.find(key);
if (it != hm.end())
{
// ...
}
The global find algorithm takes a search interval and a value as input. But it works with any container that meets some iterators constrains. In the case of a map the value is not the key, as in the unordered_map::find but the (key, value) pair. The algorithm is looking for the (key, value) pair. You can declare your target value and use it like this:
unordered_map<int, int>::value_type target{ key, value };
auto it = find(hm.begin(), hm.end(), target);
if (it != hm.end())
{
// ...
}

Using std::map with std::pair as a key and list as value

So I have the following map parseTable
std::map<std::pair<Symbol, Symbol>, list<Symbol> > parseTable;
I am confused on how to access to the list value if I have my map initialized this way:
std::map<std::pair<Symbol, Symbol>, list<Symbol> > parseTable = {
{{Symbol::Input, Symbol::OpenPar}, {Symbol::Expr, Symbol::Semicolon, Symbol::InputP}},
{{Symbol::Input, Symbol::Ident}, {Symbol::Expr, Symbol::Semicolon, Symbol::InputP}},
{{Symbol::Input, Symbol::Number}, {Symbol::Expr, Symbol::Semicolon, Symbol::InputP}}
};
I want to access to each of the values of my list individually when I use the find() function of my map.
This is what I have come up with but I am not able to get a reference to that index value:
if (parseTable.find(std::pair(stack_symbol.top(), current_symbol)))
std::map::find will return an iterator to the found element, or to end if not found. That iterator will point to a std::pair<const Key, Value>, which in your case would translate to
std::pair< const std::pair<Symbol, Symbol>, list<Symbol> >
What you want is something like this
auto it = parseTable.find(std::pair(stack_symbol.top(), current_symbol));
if (it != parseTable.end()) { // A match was found
//it->first is std::pair<Symbol, Symbol>
//it->second is list<Symbol>
for (auto& symbol : it->second) {
//symbol is each individual value in the list
... do something with symbol
}
}
This is not the greatest choice for map key, it won't let the map to be used efficiently.
std::map::find() return an iterator to the place where it found searched item or std::map::end() if not found. So, in your if statement, you need to check against that:
std::map<std::pair<Symbol, Symbol>, list<Symbol> >::iterator iter =
parseTable.find(std::pair(stack_symbol.top(), current_symbol)) //or auto with C++11
if (iter != parseTable.end())
find returns an iterator, to access the object (which will be of type std::pair<std::pair<Symbol, Symbol>, list<Symbol>>, you'll need dereference operator *
Symbol currentSymbol = (*iter).first.second; //dummy example to show the use
std::list<Symbol> myList = (*iter).second'

Pair Value Reading Errors C++

I am getting the compiler error:
error: request for member 'first' in 'list.std::map::operator[],
std::less, std::allocator > > >((* &0.0)).std::pair::second', which is
of non-class type 'int' int closestX = list[0].second.first;
when trying to read data from a map called list defined and with iterator as:
map<double, pair<int, int>> list;
map<double, pair<int, int>>::iterator it = list.begin();
Members in list are inserted with:
list.insert(it, pair<double, pair<int, int>>(findDistance(posr,posc,j, i), pair<int, int>(j, i)));
I am reading the value from the map using:
int closestX = list[0].second.first;
int closestY = list[0].second.second;
The error seems to indicate that the return type of list[0].second.first is non class type int, but that return type matches perfectly with the value type of closestX, and I have now hit a wall. Assume list[0] is initialized and holds a valid value.
list[0] is already of value type pair<int, int>, not of the iterator type. So you could write
int closestX = list[0].first;
int closestY = list[0].second;
The error seems to indicate that the return type of list[0].second.first is non class type int
No, the error message is telling that list[0].second is not class type so you can not perform .first on it.
Note that std::map::operator[] will return the mapped_type.
Returns a reference to the value that is mapped to a key equivalent to key.
list => map<double, pair<int, int>>
list[0] => pair<int, int>
list[0].second => int
list[0].second.first => failed

Can I make the following assumption when map key is not found?

std::map<std::string, int> m;
// Can I make assumption that m["NoSuchKey"] will return 0?
std::cout << m["NoSuchKey"] << std::endl;
Yes. When an item is accessed through operator[] that does not exist, it is created with a default-constructed value, and returned.
For numeric types, default-constructed means 0.
Yes. If the map key is not found, a default value will be inserted.
Specifically, operator[] is understood as:
(*((m.insert(value_type(k, data_type()))).first)).second
Translated to your case, m["NoSuchKey"] means
std::pair<std::string, int> pair_to_insert ("NoSuchKey", 0);
// default value of int is 0.
std::pair<std::map<std::string, int>::iterator, bool>
insert_res = m.insert(value_to_insert);
std::map<std::string, int>::iterator iter_of_inserted_pair = insert_res.first;
std::pair<std::string, int> inserted_pair = *iter_of_inserted_pair;
int inserted_value = inserted_pair.second;
return inserted_value;
In particular, m.insert returns the old key-value pair if the key already exists, and the new key-value pair if not. Therefore, you'll get the expected value if the key already exists, and 0 (the default value) if not.

Iterator and constant interator in C++

Whats the difference?
I want to be able to see if an element is in a HashMap and I just found out that if I do h[element], it will return the default element if it is not found, and not null. How would I use the iterator find method to see if the element is there?
Thanks
Assuming you're talking about STL and not some 3rd party library... m[key] doesn't just return the default object if key isn't in the map. It will create a new element in the map with that key and a default-constructed object as value.
You could use this:
map<string, int> mymap;
//add items to it
map<string, int>::iterator it = mymap.find("key");
if (it != myMap.end()) {
// 'key' exists; (it->second) is the corresponding int
}
Or if you don't need to get the object (you just want to know if it exists):
map<string, int> mymap;
//add items to it
if (mymap.count("key") == 1) {
// 'key' exists
}
You use the find method to see if something is in a std::map
std::map<std::string, std::string> myMap
std::map<std::string, std::string>::iterator it = myMap.find("foo");
if(it != myMap.end()) {
//foo is in the map
} else {
// foo isn't in the map
}
A const_iterator is an iterator that when de-referenced returns a const version of whatever it points to. In the example above, if it was a const_iterator then de-referencing it would yield a const std::string
The main difference is that const_iterator cannot be used to modify the value of an element in the map.
using find method
hash_map <int, int> hm1;
hash_map <int, int> :: const_iterator hm1_RcIter = hm1.find( 2 );
if ( hm1_RcIter == hm1.end( ) )
cout << "The hash_map hm1 doesn't have an element "
<< "with a key of 2." << endl;
else
cout << "The element of hash_map hm1 with a key of 4 is: "
<< hm1_RcIter -> second << "." << endl;
As the other answers explain, for a std::map you can use find.
To answer the question in the headline:
For iterators, const can refer to the iterator itself, or the to the contents, the iterator points to. Both properties are orthogonal. With STL notation you have the following cases:
iterator Contents and iterator can be modified.
const_iterator Contents is const, the iterator can be modified
const iterator Contents can be modified, the iterator is const.
const const_iterator Contents and iterator are constant.
It is similar for pointers. There, the const can also refer to the contents or the pointer itself.
const iterators are need when you want an iterator to iterate through a const container. Trying to assign a non-const modifiable iterator onto a const container will return a compiler error. This is because the non-const iterator could potentially modify the const container.