What is the best way to determine if a STL map contains a value for a given key?
#include <map>
using namespace std;
struct Bar
{
int i;
};
int main()
{
map<int, Bar> m;
Bar b = {0};
Bar b1 = {1};
m[0] = b;
m[1] = b1;
//Bar b2 = m[2];
map<int, Bar>::iterator iter = m.find(2);
Bar b3 = iter->second;
}
Examining this in a debugger, it looks like iter is just garbage data.
If I uncomment out this line:
Bar b2 = m[2]
The debugger shows that b2 is {i = 0}. (I'm guessing it means that using an undefined index will return a struct with all empty/uninitialized values?)
Neither of these methods is so great. What I'd really like is an interface like this:
bool getValue(int key, Bar& out)
{
if (map contains value for key)
{
out = map[key];
return true;
}
return false;
}
Does something along these lines exist?
As long as the map is not a multimap, one of the most elegant ways would be to use the count method
if (m.count(key))
// key exists
The count would be 1 if the element is indeed present in the map.
Does something along these lines exist?
No. With the stl map class, you use ::find() to search the map, and compare the returned iterator to std::map::end()
so
map<int,Bar>::iterator it = m.find('2');
Bar b3;
if(it != m.end())
{
//element found;
b3 = it->second;
}
Obviously you can write your own getValue() routine if you want (also in C++, there is no reason to use out), but I would suspect that once you get the hang of using std::map::find() you won't want to waste your time.
Also your code is slightly wrong:
m.find('2'); will search the map for a keyvalue that is '2'. IIRC the C++ compiler will implicitly convert '2' to an int, which results in the numeric value for the ASCII code for '2' which is not what you want.
Since your keytype in this example is int you want to search like this: m.find(2);
I just noticed that with C++20, we will have
bool std::map::contains( const Key& key ) const;
That will return true if map holds an element with key key.
It already exists with find only not in that exact syntax.
if (m.find(2) == m.end() )
{
// key 2 doesn't exist
}
If you want to access the value if it exists, you can do:
map<int, Bar>::iterator iter = m.find(2);
if (iter != m.end() )
{
// key 2 exists, do something with iter->second (the value)
}
With C++0x and auto, the syntax is simpler:
auto iter = m.find(2);
if (iter != m.end() )
{
// key 2 exists, do something with iter->second (the value)
}
I recommend you get used to it rather than trying to come up with a new mechanism to simplify it. You might be able to cut down a little bit of code, but consider the cost of doing that. Now you've introduced a new function that people familiar with C++ won't be able to recognize.
If you want to implement this anyway in spite of these warnings, then:
template <class Key, class Value, class Comparator, class Alloc>
bool getValue(const std::map<Key, Value, Comparator, Alloc>& my_map, int key, Value& out)
{
typename std::map<Key, Value, Comparator, Alloc>::const_iterator it = my_map.find(key);
if (it != my_map.end() )
{
out = it->second;
return true;
}
return false;
}
amap.find returns amap::end when it does not find what you're looking for -- you're supposed to check for that.
To succinctly summarize some of the other answers:
If you're not using C++ 20 yet, you can write your own mapContainsKey function:
bool mapContainsKey(std::map<int, int>& map, int key)
{
if (map.find(key) == map.end()) return false;
return true;
}
If you'd like to avoid many overloads for map vs unordered_map and different key and value types, you can make this a template function.
If you're using C++ 20 or later, there will be a built-in contains function:
std::map<int, int> myMap;
// do stuff with myMap here
int key = 123;
if (myMap.contains(key))
{
// stuff here
}
Check the return value of find against end.
map<int, Bar>::iterator it = m.find('2');
if ( m.end() != it ) {
// contains
...
}
You can create your getValue function with the following code:
bool getValue(const std::map<int, Bar>& input, int key, Bar& out)
{
std::map<int, Bar>::iterator foundIter = input.find(key);
if (foundIter != input.end())
{
out = foundIter->second;
return true;
}
return false;
}
Map provides 2 member functions to check if a given key exists in map with different return values i.e.
std::map::find (returns iterator)
std::map::count (returns count)
Check if map contains a key using std::map::count
It finds & returns the count of number of elements in map with key K. As map contains elements with unique key only. So, it will return 1 if key exists else 0.
Check if map contains a key using std::map::find
It checks if any element with given key ‘k’ exists in the map and if yes then it returns its iterator else
it returns the end of map.
For more details and examples refer to below link(easy to understand explanation).
Credit: https://thispointer.com/how-check-if-a-given-key-exists-in-a-map-c/
If you want to determine whether a key is there in map or not, you can use the find() or count() member function of map.
The find function which is used here in example returns the iterator to element or map::end otherwise.
In case of count the count returns 1 if found, else it returns zero(or otherwise).
if(phone.count(key))
{ //key found
}
else
{//key not found
}
for(int i=0;i<v.size();i++){
phoneMap::iterator itr=phone.find(v[i]);//I have used a vector in this example to check through map you cal receive a value using at() e.g: map.at(key);
if(itr!=phone.end())
cout<<v[i]<<"="<<itr->second<<endl;
else
cout<<"Not found"<<endl;
}
Boost multindex can be used for proper solution.
Following solution is not a very best option but might be useful in few cases where user is assigning default value like 0 or NULL at initialization and want to check if value has been modified.
Ex.
< int , string >
< string , int >
< string , string >
consider < string , string >
mymap["1st"]="first";
mymap["second"]="";
for (std::map<string,string>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
{
if ( it->second =="" )
continue;
}
Related
What is the best way to determine if a STL map contains a value for a given key?
#include <map>
using namespace std;
struct Bar
{
int i;
};
int main()
{
map<int, Bar> m;
Bar b = {0};
Bar b1 = {1};
m[0] = b;
m[1] = b1;
//Bar b2 = m[2];
map<int, Bar>::iterator iter = m.find(2);
Bar b3 = iter->second;
}
Examining this in a debugger, it looks like iter is just garbage data.
If I uncomment out this line:
Bar b2 = m[2]
The debugger shows that b2 is {i = 0}. (I'm guessing it means that using an undefined index will return a struct with all empty/uninitialized values?)
Neither of these methods is so great. What I'd really like is an interface like this:
bool getValue(int key, Bar& out)
{
if (map contains value for key)
{
out = map[key];
return true;
}
return false;
}
Does something along these lines exist?
As long as the map is not a multimap, one of the most elegant ways would be to use the count method
if (m.count(key))
// key exists
The count would be 1 if the element is indeed present in the map.
Does something along these lines exist?
No. With the stl map class, you use ::find() to search the map, and compare the returned iterator to std::map::end()
so
map<int,Bar>::iterator it = m.find('2');
Bar b3;
if(it != m.end())
{
//element found;
b3 = it->second;
}
Obviously you can write your own getValue() routine if you want (also in C++, there is no reason to use out), but I would suspect that once you get the hang of using std::map::find() you won't want to waste your time.
Also your code is slightly wrong:
m.find('2'); will search the map for a keyvalue that is '2'. IIRC the C++ compiler will implicitly convert '2' to an int, which results in the numeric value for the ASCII code for '2' which is not what you want.
Since your keytype in this example is int you want to search like this: m.find(2);
I just noticed that with C++20, we will have
bool std::map::contains( const Key& key ) const;
That will return true if map holds an element with key key.
It already exists with find only not in that exact syntax.
if (m.find(2) == m.end() )
{
// key 2 doesn't exist
}
If you want to access the value if it exists, you can do:
map<int, Bar>::iterator iter = m.find(2);
if (iter != m.end() )
{
// key 2 exists, do something with iter->second (the value)
}
With C++0x and auto, the syntax is simpler:
auto iter = m.find(2);
if (iter != m.end() )
{
// key 2 exists, do something with iter->second (the value)
}
I recommend you get used to it rather than trying to come up with a new mechanism to simplify it. You might be able to cut down a little bit of code, but consider the cost of doing that. Now you've introduced a new function that people familiar with C++ won't be able to recognize.
If you want to implement this anyway in spite of these warnings, then:
template <class Key, class Value, class Comparator, class Alloc>
bool getValue(const std::map<Key, Value, Comparator, Alloc>& my_map, int key, Value& out)
{
typename std::map<Key, Value, Comparator, Alloc>::const_iterator it = my_map.find(key);
if (it != my_map.end() )
{
out = it->second;
return true;
}
return false;
}
amap.find returns amap::end when it does not find what you're looking for -- you're supposed to check for that.
To succinctly summarize some of the other answers:
If you're not using C++ 20 yet, you can write your own mapContainsKey function:
bool mapContainsKey(std::map<int, int>& map, int key)
{
if (map.find(key) == map.end()) return false;
return true;
}
If you'd like to avoid many overloads for map vs unordered_map and different key and value types, you can make this a template function.
If you're using C++ 20 or later, there will be a built-in contains function:
std::map<int, int> myMap;
// do stuff with myMap here
int key = 123;
if (myMap.contains(key))
{
// stuff here
}
Check the return value of find against end.
map<int, Bar>::iterator it = m.find('2');
if ( m.end() != it ) {
// contains
...
}
You can create your getValue function with the following code:
bool getValue(const std::map<int, Bar>& input, int key, Bar& out)
{
std::map<int, Bar>::iterator foundIter = input.find(key);
if (foundIter != input.end())
{
out = foundIter->second;
return true;
}
return false;
}
Map provides 2 member functions to check if a given key exists in map with different return values i.e.
std::map::find (returns iterator)
std::map::count (returns count)
Check if map contains a key using std::map::count
It finds & returns the count of number of elements in map with key K. As map contains elements with unique key only. So, it will return 1 if key exists else 0.
Check if map contains a key using std::map::find
It checks if any element with given key ‘k’ exists in the map and if yes then it returns its iterator else
it returns the end of map.
For more details and examples refer to below link(easy to understand explanation).
Credit: https://thispointer.com/how-check-if-a-given-key-exists-in-a-map-c/
If you want to determine whether a key is there in map or not, you can use the find() or count() member function of map.
The find function which is used here in example returns the iterator to element or map::end otherwise.
In case of count the count returns 1 if found, else it returns zero(or otherwise).
if(phone.count(key))
{ //key found
}
else
{//key not found
}
for(int i=0;i<v.size();i++){
phoneMap::iterator itr=phone.find(v[i]);//I have used a vector in this example to check through map you cal receive a value using at() e.g: map.at(key);
if(itr!=phone.end())
cout<<v[i]<<"="<<itr->second<<endl;
else
cout<<"Not found"<<endl;
}
Boost multindex can be used for proper solution.
Following solution is not a very best option but might be useful in few cases where user is assigning default value like 0 or NULL at initialization and want to check if value has been modified.
Ex.
< int , string >
< string , int >
< string , string >
consider < string , string >
mymap["1st"]="first";
mymap["second"]="";
for (std::map<string,string>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
{
if ( it->second =="" )
continue;
}
My code is as below.
I have as struct ABC and i have set g_ABCSet to compare the id.
struct ABC
{
CString name;
byte id[2];
}
typedef shared_ptr<ABC> ABC_PTR;
std::set<ABC_PTR, CompareABC> g_ABCSet;
class ComparePager{
public:
bool operator()(const ABC_PTR& m1, const ABC_PTR& m2) const {
if (m1->id[0] == m2->id[0]){
return m1->id[1] < m2->id[1];
}
return m1->id[0] < m2->id[0];
}
}
I try to search in set as below comparing the id
static ABC_PTR ABCptr(new ABC);
//Assume ABCptr have some valid ID
auto it = g_ABCSet.find(ABCptr);
if (it == g_ABCSet.end())
{
//not found
}
else
{
//found one
}
My query here is can i use the same set to compare the "Cstring name" in the ABC struct.
If YES HOW ??
IF NO , DO i need to make same new set ,overlaod operator to comparing Cstring and insert all same pointers to new set also ??
No you cannot use a single std::set.
Why: Because the set requires the keys to be in 'strict ordering'. Most likely the set uses a tree structure to store it's items and the tree is sorted by the given comparator.
This means also that if you insert multiple items with different names and identical ids, only one items is stored at all (because the Comparator says they are all identical)
You can use std::find_if to search for Cstring name:
CString searchName = "...";
auto it = std::find_if(
g_ABCSet.begin(),
g_ABCSet.end(),
[&](const ABC_PTR& ptr) {
return ptr->name == searchName;
});
If you have a large set of items in g_ABCSet you should do as you wrote: create a second set with a Comparator for 'name'.
Tip: If you use std::array<byte, 2> id instead of byte id[2] your Comparator could be as simple as
class ComparePager{
public:
bool operator()(const ABC_PTR& m1, const ABC_PTR& m2) const {
return m1->id < m2->id;
}
}
Maybe you better use a std::map<std::array<byte, 2>, ABC_PTR> and another std::map<CString, ABC_PTR> for this job. This needs more memory (mostly because of the CString being copied from the g_ABCSet into the map) but get completly rid of the custom Comparators and you cannot accidentally use the wrong set (with the wrong Comparator)
I am using an unordered_map of unordered_maps, such that I can reference an element using the "multi key" syntax:
my_map[k1][k2].
Is there a convenient way to use the same "multi-key" syntax to check whether an element exists before trying to access it? If not, what is the simplest way?
If your intention is to test for the existence of the key, I would not use
my_map[k1][k2]
because operator[] will default construct a new value for that key if it does not already exist.
Rather I would prefer to use std::unordered_map::find. So if you are certain the first key exists, but not the second you could do
if (my_map[k1].find(k2) != my_map[k1].end())
{
// k2 exists in unordered_map for key k1
}
If you would like to make a function that checks for the existence of both keys, then you could write something like
//------------------------------------------------------------------------------
/// \brief Determines a nested map contains two keys (the outer containing the inner)
/// \param[in] data Outer-most map
/// \param[in] a Key used to find the inner map
/// \param[in] b Key used to find the value within the inner map
/// \return True if both keys exist, false otherwise
//------------------------------------------------------------------------------
template <class key_t, class value_t>
bool nested_key_exists(std::unordered_map<key_t, std::unordered_map<key_t, value_t>> const& data, key_t const a, key_t const b)
{
auto itInner = data.find(a);
if (itInner != data.end())
{
return itInner->second.find(b) != itInner->second.end();
}
return false;
}
template<class M>
bool contains(M const&){return true;}
template<class M, class K, class...Ks>
bool contains(M const&m, K const&k, Ks const&...ks){
auto it=m.find(k);
if (it==m.end()) return false;
return contains(it->second, ks...);
}
will work for every single-valued associative container.
contains(my_map, k1, k2) is true if there is an element k1 which contains k2.
In C++20, you can use the contains method (added to all associative containers if I am not mistaken):
if (my_map.contains(k1) && my_map[k1].contains(k2))
{
// do something with my_map[k1][k2]
}
You might also use count (http://www.cplusplus.com/reference/unordered_map/unordered_map/count/ )
which will return 0 if key not exist
Something like this? (for the mutable case)
using inner_map = std::map<key_type, value_type>;
using outer_map = std::map<key_type, inner_map>
boost::optional<value_type&>
element_for_keys(outer_map& map, const key_type& k1, const key_type& k2)
{
auto it_outer = map.find(k1);
if (it_outer = map.end())
return {};
auto &map2 = it_outer->second;
auto it_inner = map2.find(k2);
if (it_inner == map2.end())
return {};
return { it_inner->second };
}
called like so:
auto op_value = element_for_keys(my_map, kv1, kv2);
if (op_value) {
// use op_value.value()
}
else {
// handle case where it does not exist
}
... or there's the more python-like way...
try {
auto& v = my_map.at(k1).at(k2);
// use v
}
catch(const std::out_of_range & e) {
// didn't find it
}
I don't believe there is a multi-key syntax to check, but the simplest way would be to use the find method. You could write a simple function to apply it to a unordered_map of unordered_maps
reference
An alternative approach is to use std::pair as key to transforming the two-level hashtable into one level hashtable, the benefit:
Simpler code and structure
Maybe faster than two-level hash table(We call fewer hash functions, get more compacted memory layout to be more cache-friendly)
The drawback: We have some key redundancy, so it would be a bad choice for large keys with many duplications, but this scenario won't be too common so the strategy here is still useful.
std::unordered_map<std::pair<int, int>, int> map;
Then to check exists:
With find and compare with end iterator
map.find(std::make_pair(k0, k1)) != map.end()
With the count function(Be aware that don't use it with unordered_multimap)
map.count(std::make_pair(k0, k1)) != 0
or C++20 contains:
map.contains(std::make_pair(k0, k1))
I am trying to return content of std::pair which has int and string values.
What return type for function should I keep?
I tried with both int and char return type but gives error for both. I have given error below:
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
std::pair<int,std::string>client()
{
std::vector<std::string> most { "lion","tiger","kangaroo",
"donkey","lion","tiger",
"lion","donkey","tiger"
};
std::map<std::string, int> src;
for(auto x:most)
++src[x];
std::multimap<int,std::string,std::greater<int> > dst;
std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()),
[] (const std::pair<std::string,int> &p) {
return std::pair<int,std::string>(p.second, p.first);
}
);
std::multimap<int,std::string>::iterator it = dst.begin();
for(int count = 0;count<3 && it !=dst.end();++it,++count)
std::cout<<it->second<<":"<<it->first<<std::endl;
return *it;
}
int main()
{
std::multimap<int,std::string>::const_iterator rec;
rec= client(); // Error no match for ‘operator=’ in ‘rec = client()()’
std::multimap<int,std::string>::iterator it = rec.begin(); //error: ‘std::multimap<int, std::basic_string<char> >::const_iterator’ has no member named ‘begin’
for(int count = 0;count<3 && rec !=it.end();++it,++count) // error: has no member named 'end'
std::cout<<rec->second<<":"<<rec->first<<std::endl;
}
Just return the pair of int & std::string itself
as the multimap contains that as its element
std::pair<int,std::string> client(){
//...
}
If you want to return the map entry (i.e., both the key and value), then just use std::pair<int, std::string> as the return type, as other answers mentioned.
If you want to just return the key, return it->first (and use int as the return type). If you want to return just the value, return it->second (and use std::string as the return type).
If you want to return the a value from a std::map I would not explicitly use std::pair (though it is perfectly fine to do so). Personally I would use the std::map::value_type which represents the type of the values stored in the map (note: all containers have a type member called value_type that represents the type being stored).
std::multimap<int,std::string>::value_type client()
{
// STUFF
std::multimap<int,std::string>::iterator it = dst.begin();
// STUFF;
return *it; // Note: this is UB if it == dst.end()
}
The reason I would use value_type rather than std::pair is normally I would not use explicit types but would have created typedefs (so it looks like this).
typedef std::multimap<int,std::string> MapForX; // Modification to map here
// Will automatically roll threw all
// the following code as everything
// is defined in terms of `MapForX`
MapForX::value_type client()
{
// STUFF
MapForX::iterator it = dst.begin();
// STUFF;
return *it; // Note: this is UB if it == dst.end()
}
Now if I change the type of the MapForX. Then I only have to change one thing (the single typedef). If you return std::pair<int,std::string> then you have to make changes in two places (the typedef and the return value). Which to me is redundant change that can cause problems.
As a demo: If you return std::pair<int, std::string> your code looks like this:
typedef std::multimap<int,std::string> MapForX; // Modification to map here
// Will automatically roll threw MOST
// the following code.
// But notice this return type is not defined in terms of MapForX
// Thus if you change MapForX you will also need to change the return type.
// to match the correct type.
std::pair<int, std::string> client()
{
// STUFF
MapForX::iterator it = dst.begin();
// STUFF;
return *it; // Note: this is UB if it == dst.end()
}
That works perfectly well. But in the future you have to make some changes. And you change the type of the map too int => MySpecialType. Now in my second example (with the typedef) you only need to make one change (in MapForX). In the example above you need to make two changes (one for MapForX and one std::pair on the return type).
#Martin York: You have good intentions but have you checked them against reality? Because value_type is exported as std::pair<const key_type, mapped_type>:
https://en.cppreference.com/w/cpp/container/map
This may work if you return a copy of a pair from an iterator. It won't work if you construct that pair within the function and then try to fill it because first can't be modified.
When the goal is to avoid the k/v types twice:
using the_map_value_type = std::pair<the_map::key_type, the_map::mapped_type>
Then use this type as a function result. Of course, only until the negligence has been eliminated in the STL with an export like detached_value_type.
I have a map named valueMap as follows:
typedef std::map<std::string, std::string>MAP;
MAP valueMap;
...
// Entering data.
Then I am passing this map to a function by reference:
void function(const MAP &map)
{
std::string value = map["string"];
// By doing so I am getting an error.
}
How can I get the value from the map, which is passed as a reference to a function?
std::map::operator[] is a non-const member function, and you have a const reference.
You either need to change the signature of function or do:
MAP::const_iterator pos = map.find("string");
if (pos == map.end()) {
//handle the error
} else {
std::string value = pos->second;
...
}
operator[] handles the error by adding a default-constructed value to the map and returning a reference to it. This is no use when all you have is a const reference, so you will need to do something different.
You could ignore the possibility and write string value = map.find("string")->second;, if your program logic somehow guarantees that "string" is already a key. The obvious problem is that if you're wrong then you get undefined behavior.
map.at("key") throws exception if missing key.
If k does not match the key of any element in the container, the
function throws an out_of_range exception.
http://www.cplusplus.com/reference/map/map/at/
The answer by Steve Jessop explains well, why you can't use std::map::operator[] on a const std::map. Gabe Rainbow's answer suggests a nice alternative. I'd just like to provide some example code on how to use map::at(). So, here is an enhanced example of your function():
void function(const MAP &map, const std::string &findMe) {
try {
const std::string& value = map.at(findMe);
std::cout << "Value of key \"" << findMe.c_str() << "\": " << value.c_str() << std::endl;
// TODO: Handle the element found.
}
catch (const std::out_of_range&) {
std::cout << "Key \"" << findMe.c_str() << "\" not found" << std::endl;
// TODO: Deal with the missing element.
}
}
And here is an example main() function:
int main() {
MAP valueMap;
valueMap["string"] = "abc";
function(valueMap, "string");
function(valueMap, "strong");
return 0;
}
Output:
Value of key "string": abc
Key "strong" not found
Code on Ideone
The main problem is that operator[] is used to insert and read a value into and from the map, so it cannot be const.
If the key does not exist, it will create a new entry with a default value in it, incrementing the size of the map, that will contain a new key with an empty string ,in this particular case, as a value if the key does not exist yet.
You should avoid operator[] when reading from a map and use, as was mention before, map.at(key) to ensure bound checking. This is one of the most common mistakes people often do with maps. You should use insert and at unless your code is aware of this fact. Check this talk about common bugs Curiously Recurring C++ Bugs at Facebook
How can I get the value from the map, which is passed as a reference to a function?
Well, you can pass it as a reference. The standard reference wrapper that is.
typedef std::map<std::string, std::string> MAP;
// create your map reference type
using map_ref_t = std::reference_wrapper<MAP>;
// use it
void function(map_ref_t map_r)
{
// get to the map from inside the
// std::reference_wrapper
// see the alternatives behind that link
MAP & the_map = map_r;
// take the value from the map
// by reference
auto & value_r = the_map["key"];
// change it, "in place"
value_r = "new!";
}
And the test.
void test_ref_to_map() {
MAP valueMap;
valueMap["key"] = "value";
// pass it by reference
function(valueMap);
// check that the value has changed
assert( "new!" == valueMap["key"] );
}
I think this is nice and simple. Enjoy ...
Although it's kinda late but I am still gonna answer, thanks to previous answers on this question i was able to forge this class which reuse pointers and values, it creates two maps to store data, Here the code if anybody interested..
template<class T1, class T2> class Bimap
{
std::map<T1, T2*> map1;
std::map<T2, T1*> map2;
public:
void addRow(T1 &t1, T2 &t2){
map1.insert(make_pair(t1, &t2));
map2.insert(make_pair(t2, &t1));
}
T2* findForward(T1 t1){
T2* value = map1.find(t1)->second;
return value;
}
T1* findBackward(T2 t2){
T1* value = map2.find(t2)->first;
return value;
}
};
Using class:
//Init mapp with int,int
Bimap<int,int> mapp;
//Add a row(Record) in bimap
int a = 5;
int b = 7002;
mapp.addRow(a, b);
//Print a record
int *ans= mapp.findForward(a);
cout<<"Bimap Returned:"<<*ans<<endl;