Find value of index in Map Array using string key - c++

In an array map<string, int> bannd such that each key (of type string) holds a number value, like this
+++++++++++++++
key | value
+++++++++++++++
red | 0
blue | 1
orange| 3
etc...
What is the optimal way to return the value of an index using the key?
I already tried using find like this
band1 = band.find("a");
where a is the key value in the map, but it does not seem to be working.

find returns an iterator pointing to the found key-value pair (if any). You have to dereference that iterator to get the actual mapped value:
int band1;
auto it = band.find("a");
if (it != band.end())
band1 = it->second;
else
/* not found ... */;
Note that *it just gives us the std::pair containing the key and mapped value together. To access the mapped value itself we use it->second.
Alternatively, if you know that the key is in the map, you can use at to get the mapped value for that key:
int band1 = band.at("a");
at will throw an out_of_range exception if the element is not found.
Finally, if you want to access the value with key "a" and you want to automatically add that key to the map if it is not already there, you can use the subscript operator []:
int band1 = band["a"]; //warning: inserts {a, 0} into the map if not found!

Write a function, which takes std::map and std::vector of key as argument. And it will return the corresponding values in std::vector
vector<int> valueReturn(map<string,int> data, vector<string> key) {
vector<int> value;
for(const auto& it: key) {
auto search = data.find(it);
if(search != data.end()) {
value.push_back(data[it]);
std::cout << "Found " << search->first << " " << search->second << '\n';
}
else {
value.push_back(-1); // Inserting -1 for not found value, You can insert some other values too. Which is not used as value
std::cout << "Not found\n";
}
}
return value;
}

int band1 = band["a"];
int band2 = band["b"];
int band3 = band["c"];
int band4 = band["d"];

Related

Is unordered map behaving as expected in C++?

I am new to C++ and I don't get to understand the logic of the following code:
#include <unordered_map>
std::unordered_map<int, int> maxima;
void update(int key, int value) {
auto it = maxima.find(key);
if (it == maxima.end()) {
maxima.emplace(key, value);
} else if (value > it->second) {
it->second = value;
}
}
I have tested it with the following:
int main() {
update(3,6);
update(1,6);
update(4,6);
update(4,9);
update(2,9);
update(1,3);
update(3,18);
for (auto x : maxima)
cout << x.first << " " << x.second << endl;
return 0;
}
and it returns:
2 9
4 9
1 6
3 18
How come the (1,3) has disappeared from the output?
The update function can be read as if the key is not present then add the key/value pair to the map, otherwise if the new value is greater than the existing value then replace the existing value with the new value, otherwise do nothing.
I'm sure you can see that under this rule the (1,3) pair never gets added because of the existing (1,6) pair.
The overall logic is to store in the unordered map the maximum value associated with any given key. For the key of 1 that value is 6.

incrementing the value in map using insert c++

I have the following problem - I want to count the occurrences of each word in a file. I'm using a map<string,Count> so the key is the string object representing the word, and the value being looked up is the object that keeps count of the strings so that :
class Count {
int i;
public:
Count() : i(0) {}
void operator++(int) { i++; } // Post-increment
int& val() { return i; }
};
The problem is that I want to use insert() instead of the operator[]. Here is the code.
typedef map<string, Count> WordMap;
typedef WordMap::iterator WMIter;
int main( ) {
ifstream in("D://C++ projects//ReadF.txt");
WordMap wordmap;
string word;
WMIter it;
while (in >> word){
// wordmap[word]++; // not that way
if((it= wordmap.find(word)) != wordmap.end()){ //if the word already exists
wordmap.insert(make_pair(word, (*it).second++); // how do I increment the value ?
}else{
...
}
for (WMIter w = wordmap.begin();
w != wordmap.end(); w++)
cout << (*w).first << ": "
<< (*w).second.val() << endl;
}
Could you refactor so as not to use find but simply attempt the insert?
Insert always returns a pair<iter*, bool>. The bool is 0 if it finds the key, and the iter* points to the existing pair. So we can take the pointer to the pair and increment the value:
// On successful insertion, we get a count of 1 for that word:
auto result_pair = wordmap.insert( { word, 1 } );
// Increment the count if the word is already there:
if (!result_pair.second)
result_pair.first->second++;
It was my first time posting. I'm learning C++ and welcome feedback on my idea.
The problem is that I want to use insert() instead of the operator[]
...why? std::map::insert cannot mutate existing values. operator[] is the right job for this.
If you really want to use insert (please don't), you first need to erase the existing value, if present:
if((it= wordmap.find(word)) != wordmap.end())
{
const auto curr = it->second; // current number of occurrences
wordmap.erase(word);
wordmap.insert(make_pair(word, curr + 1));
}

boost::unordered_multimap: get all elements in bucket efficiently?

I can get all elements in a single bucket with this code:
typedef boost::unordered_multimap< key, myClass*, MyHash<key> >
HashMMap;
HashMMap::iterator it;
it = hashMMap_.find( someKey);
int bucketIndex = hashMMap_.bucket( someKey);
int bucketSize = hashMMap_.bucket_size( bucketIndex);
qDebug() << "index of bucket with key:" << someKey << " is:"
<< bucketIndex;
qDebug() << "number of elements in bucket with index:" << bucketIndex << " is:"
<< bucketSize;
HashMMap::local_iterator lit;
/* begin of bucket with index bucketIndex */
lit = hashMMap_.begin( bucketIndex);
for ( ; lit != sender_.hashMMap_.end( bucketIndex); ++lit) {
qDebug() << "(*lit).first:" << (*lit).first << ", (*lit).second:" <<
(*lit).second << ", (*lit).second->something_:" <<
(*lit).second->something_;
}
I would like to get a local_iterator to the first element in a bucket and iterate over it till the bucket end, so if there is only one value for a given index in hash table (where index is the Hash(key)) I will iterate just through a single element and receive bucket end(), and in case of many elements I will iterate whole bucket (all values with equal hash). is this possible without bucketIndex, hashMMap_.begin( bucketIndex) and hashMMap_.end( bucketIndex) ?
so basically I would like to get a local_iterator like this:
HashMMap::local_iterator lit = hashMMap_.find_bucket_if_present( someKey);
Additional question is: do I have to test first if find() returns an iterator to element before calling int bucketIndex = hashMMap_.bucket( someKey) ? This is what I think because explanation of bucket() function from boost site is:
Returns: The index of the bucket which would contain an element with
key k.
^^^
I think this means I have first to find(key) in the multimap to know if key is present, because a call to bucket(key) will return an index which is not a hash but modulo of hash (bucket_from_hash) in the hash table under which key is stored if it is present. So because of the modulo which is done with bucket_count, if key was not inserted I will iterate over a virtual bucket in which it would be under current circumstances, and what is most important for me: also different hashes could be there as the bucket_count might be less than my hash (I use 16-bit MyHash<key> of 32-bit key as a hash function provided into multimap constructor). Is this correct?
I would start working with ranges, like so:
template<typename BoostUnorderedMap, typename Key>
boost::iterator_range< typename BoostUnorderedMap::local_iterator > get_bucket_range( BoostUnorderedMap& myMap, Key const& k ) {
int bucketIndex = myMap.bucket( k );
return boost::iterator_range< typename BoostUnorderedMap::local_iterator >(
myMap.begin(bucketIndex),
myMap.end(bucketIndex)
}
}
template<typename BoostUnorderedMap, typename Key>
boost::iterator_range< typename BoostUnorderedMap::local_const_iterator > get_bucket_range( BoostUnorderedMap const& myMap, Key const& k ) {
int bucketIndex = myMap.bucket( k );
return boost::iterator_range< typename BoostUnorderedMap::local_const_iterator >(
myMap.begin(bucketIndex),
myMap.end(bucketIndex)
}
}
then, at least in C++11, you can do the following:
for (auto && entry : get_bucket_range( some_map, "bob" ) )
and it iterates over everything in the "bob" bucket.
While this does use bucketIndex, it hides these details from the end consumer, and simply gives you a boost::range instead.

C++: Map, previous item of a key

I have this map: map<int, int > items.
Given a key, I want that this map returns the item corrisponding to the key if it present, otherwise the map returns the item with key immediately less than the given key.
For example, if I have:
items[0]=0;
items[6]=10;
items[15]=18;
items[20]=22;
than for key=15, I want that the map returns item with value 18, otherwise for key=9, I want that map returns item with value 10.
I haven't find a function for this case. But I tried in this way:
itlow=items.lower_bound(key);
if(!items.count(key))
itlow--;
return itlow->second;
This works as I want, entering in the map a min value items[0]=0 for default, but I know that itlow--; it's not good programming. How can I do? thanks all.
You just need to check if your itlow is already items.begin(). If it is, there's no such element in the map:
itlow=items.lower_bound(key);
if(itlow->first == key)
return itlow->second;
else if(itlow != items.begin())
itlow--;
return itlow->second;
else
throw some_exception();
Instead of throwing exception, you may return iterator, and then you can return items.end() if no such element is found.
#include <iostream>
#include <map>
using namespace std;
map<int, int>::const_iterator find(const map<int, int> &items, int value)
{
auto itlow = items.lower_bound(value);
if(itlow->first == value)
return itlow;
else if(itlow != items.cbegin())
return --itlow;
else
return items.cend();
}
int main()
{
map<int, int> items;
items[2]=0;
items[6]=10;
items[15]=18;
items[20]=22;
auto i = find(items, 0);
if(i != items.cend())
{
cout << i->second << endl;
}
i = find(items, 15);
if(i != items.cend())
{
cout << i->second << endl;
}
i = find(items, 9);
if(i != items.cend())
{
cout << i->second << endl;
}
}
Try this
auto it = prev(map.upper_bound(key));
This works because map.upper_bound returns an iterator pointing to the first element that is greater than key or the past-the-end iterator when such element does not exist. Also, OP explained that map is not empty and key is greater than the first element in the map. If the latter conditions are not met, one should handle separately the case where upper_bound returns map.begin().

How to find if a given key exists in a C++ std::map

I'm trying to check if a given key is in a map and somewhat can't do it:
typedef map<string,string>::iterator mi;
map<string, string> m;
m.insert(make_pair("f","++--"));
pair<mi,mi> p = m.equal_range("f");//I'm not sure if equal_range does what I want
cout << p.first;//I'm getting error here
so how can I print what is in p?
Use map::find and map::end:
if (m.find("f") == m.end()) {
// not found
} else {
// found
}
To check if a particular key in the map exists, use the count member function in one of the following ways:
m.count(key) > 0
m.count(key) == 1
m.count(key) != 0
The documentation for map::find says: "Another member function, map::count, can be used to just check whether a particular key exists."
The documentation for map::count says: "Because all elements in a map container are unique, the function can only return 1 (if the element is found) or zero (otherwise)."
To retrieve a value from the map via a key that you know to exist, use map::at:
value = m.at(key)
Unlike map::operator[], map::at will not create a new key in the map if the specified key does not exist.
C++20 gives us std::map::contains to do that.
#include <iostream>
#include <string>
#include <map>
int main()
{
std::map<int, std::string> example = {{1, "One"}, {2, "Two"},
{3, "Three"}, {42, "Don\'t Panic!!!"}};
if(example.contains(42)) {
std::cout << "Found\n";
} else {
std::cout << "Not found\n";
}
}
You can use .find():
map<string,string>::iterator i = m.find("f");
if (i == m.end()) { /* Not found */ }
else { /* Found, i->first is f, i->second is ++-- */ }
C++17 simplified this a bit more with an If statement with initializer.
This way you can have your cake and eat it too.
if ( auto it{ m.find( "key" ) }; it != std::end( m ) )
{
// Use `structured binding` to get the key
// and value.
const auto&[ key, value ] { *it };
// Grab either the key or value stored in the pair.
// The key is stored in the 'first' variable and
// the 'value' is stored in the second.
const auto& mkey{ it->first };
const auto& mvalue{ it->second };
// That or just grab the entire pair pointed
// to by the iterator.
const auto& pair{ *it };
}
else
{
// Key was not found..
}
m.find == m.end() // not found
If you want to use other API, then find go for m.count(c)>0
if (m.count("f")>0)
cout << " is an element of m.\n";
else
cout << " is not an element of m.\n";
I think you want map::find. If m.find("f") is equal to m.end(), then the key was not found. Otherwise, find returns an iterator pointing at the element found.
The error is because p.first is an iterator, which doesn't work for stream insertion. Change your last line to cout << (p.first)->first;. p is a pair of iterators, p.first is an iterator, p.first->first is the key string.
A map can only ever have one element for a given key, so equal_range isn't very useful. It's defined for map, because it's defined for all associative containers, but it's a lot more interesting for multimap.
template <typename T, typename Key>
bool key_exists(const T& container, const Key& key)
{
return (container.find(key) != std::end(container));
}
Of course if you wanted to get fancier you could always template out a function that also took a found function and a not found function, something like this:
template <typename T, typename Key, typename FoundFunction, typename NotFoundFunction>
void find_and_execute(const T& container, const Key& key, FoundFunction found_function, NotFoundFunction not_found_function)
{
auto& it = container.find(key);
if (it != std::end(container))
{
found_function(key, it->second);
}
else
{
not_found_function(key);
}
}
And use it like this:
std::map<int, int> some_map;
find_and_execute(some_map, 1,
[](int key, int value){ std::cout << "key " << key << " found, value: " << value << std::endl; },
[](int key){ std::cout << "key " << key << " not found" << std::endl; });
The downside to this is coming up with a good name, "find_and_execute" is awkward and I can't come up with anything better off the top of my head...
map<string, string> m;
check key exist or not, and return number of occurs(0/1 in map):
int num = m.count("f");
if (num>0) {
//found
} else {
// not found
}
check key exist or not, and return iterator:
map<string,string>::iterator mi = m.find("f");
if(mi != m.end()) {
//found
//do something to mi.
} else {
// not found
}
in your question, the error caused by bad operator<< overload, because p.first is map<string, string>, you can not print it out. try this:
if(p.first != p.second) {
cout << p.first->first << " " << p.first->second << endl;
}
Be careful in comparing the find result with the the end like for map 'm' as all answer have
done above
map::iterator i = m.find("f");
if (i == m.end())
{
}
else
{
}
you should not try and perform any operation such as printing the key or value with iterator i if its equal to m.end() else it will lead to segmentation fault.
Comparing the code of std::map::find and std::map::count, I'd say the first may yield some performance advantage:
const_iterator find(const key_type& _Keyval) const
{ // find an element in nonmutable sequence that matches _Keyval
const_iterator _Where = lower_bound(_Keyval); // Here one looks only for lower bound
return (_Where == end()
|| _DEBUG_LT_PRED(this->_Getcomp(),
_Keyval, this->_Key(_Where._Mynode()))
? end() : _Where);
}
size_type count(const key_type& _Keyval) const
{ // count all elements that match _Keyval
_Paircc _Ans = equal_range(_Keyval); // Here both lower and upper bounds are to be found, which is presumably slower.
size_type _Num = 0;
_Distance(_Ans.first, _Ans.second, _Num);
return (_Num);
}
I know this question already has some good answers but I think my solution is worth of sharing.
It works for both std::map and std::vector<std::pair<T, U>> and is available from C++11.
template <typename ForwardIterator, typename Key>
bool contains_key(ForwardIterator first, ForwardIterator last, Key const key) {
using ValueType = typename std::iterator_traits<ForwardIterator>::value_type;
auto search_result = std::find_if(
first, last,
[&key](ValueType const& item) {
return item.first == key;
}
);
if (search_result == last) {
return false;
} else {
return true;
}
}
map <int , char>::iterator itr;
for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
{
if (itr->second == 'c')
{
cout<<itr->first<<endl;
}
}
If you want to compare pair of map you can use this method:
typedef map<double, double> TestMap;
TestMap testMap;
pair<map<double,double>::iterator,bool> controlMapValues;
controlMapValues= testMap.insert(std::pair<double,double>(x,y));
if (controlMapValues.second == false )
{
TestMap::iterator it;
it = testMap.find(x);
if (it->second == y)
{
cout<<"Given value is already exist in Map"<<endl;
}
}
This is a useful technique.