finding all the values with given key for multimap - c++

I am searching for all pairs for a particular key in a multimap using the code below.
int main() {
multimap<int,int> mp;
mp.insert({1,2});
mp.insert({11,22});
mp.insert({12,42});
mp.insert({1,2});
mp.insert({1,2});
for (auto itr = mp.find(1); itr != mp.end(); itr++)
cout << itr->first<< '\t' << itr->second << '\n';
}

You're calling find only a single time in your code. It's perfectly acceptable for this call to return the same value as mp.begin() resulting in you iterating though all the entries in the map before reaching mp.end().
You can use the equal_range member function to get iterators for the start and end of the elements with key 1:
for (auto[itr, rangeEnd] = mp.equal_range(1); itr != rangeEnd; ++itr)
{
std::cout << itr->first<< '\t' << itr->second << '\n';
}

Like others pointed out your code looped all the elements, from the first iterator (find(1) retuned the first iterator) to last.
If you want you can use C++20 ranges (#include <ranges>)
//DATA
std::multimap<int, int> mp;
mp.insert({ 1,2 });
mp.insert({ 11,22 });
mp.insert({ 12,42 });
mp.insert({ 1,3 });
mp.insert({ 1,4 });
//FILTER THE ELEMENTS
auto foundElements = mp | std::views::filter([](auto& v) {
return v.first == 1;
});
//PRINT
for (auto m : foundElements)
{
std::cout << m.first << " " << m.second << std::endl;
}

Related

How to endlessly loop over map

I need to iterate over the entire map without stopping the loop.
My example works but it uses two loops, can this be fixed?
I think it's possible to do this using only one for loop
#include <map>
map<int, int>map2;
map2[1] = 11;
map2[2] = 12;
map2[3] = 13;
for (;;)
{
for (auto& a : map2)
{
cout << a.first << " : " << a.second << '\n';
}
}
Use the std::map::iterator. That way you can just check if the iterator is at the end and if so reset it to the beginning.
map<int, int>::iterator it;
for ( it = map2.begin(); it != map2.end(); it == std::prev( map2.end() ) ? it = map2.begin() : it++ )
{
cout << it->first << " : " << it->second << '\n';
}
Clarification
it == std::prev( map2.end() ) ? it = map2.begin() : it++
That is the ternary operator. You first ask if the iterator is equal to the last element in the map. We add the std::prev() in order to get the last element as map::end() provides us with a past-the-end value.
it == std::prev(map2.end())
If it is the last element you set the iterator to the beginning of the map.
it = map2.begin()
Else the iterator is incremented and you get the next element
it++
See also: Loop through map

How to handle std::find_if() returning false?

Take the following example taken from the cplusplus.com reference page and altered to return false:
// find_if example
#include <iostream> // std::cout
#include <algorithm> // std::find_if
#include <vector> // std::vector
bool IsOdd (int i) {
return ((i%2)==1);
}
int main ()
{
std::vector<int> myvector;
myvector.push_back(10);
myvector.push_back(20);
myvector.push_back(40);
myvector.push_back(50);
std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
std::cout << "The first odd value is " << *it << '\n';
return 0;
}
Since no value in myvector is odd it will return InputIterator last, which is undefined:
The first odd value is -1727673935
What is the proper way to handle this output?
How can I know std::find_if() returned false if the output is unpredictable and comparing to the entire vector to confirm the resulting value doesn't exist defeats the purpose of using std::find_if() to begin with?
Do you mean
std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
if ( it != myvector.end() )
{
std::cout << "The first odd value is " << *it << '\n';
}
else
{
// std::cout << "there is no odd value in the vector\n";
}
The idiomatic way to do this is to check whether the iterator equals the end sentinel.
auto it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
if (it == myvector.end()) {
std::cout << "No odd values found" << std::endl;
} else {
std::cout << "The first odd value is " << *it << std::endl;
}
In C++17 (the most recent standard), you can declare the iterator right in the if statement:
if (auto it = std::find_if(myvector.begin(), myvector.end(), IsOdd); it != myvector.end()) {
std::cout << "The first odd value is " << *it << std::endl;
} else {
std::cout << "No odd values found" << std::endl;
}
You need to check if the returned iterator is the end iterator you passed to std::find_if (the second argument). These semantics are quite common for algorithms in the standard library, so you should get used to this.
const auto firstOdd = std::find_if (myvector.cbegin(), myvector.cend(), IsOdd);
if (firstOdd != myvector.cend())
std::cout << "The first odd value is " << *it << '\n';
else
std::cout << "No odd values found\n";
Note also that you can use the cbegin()/cend() member functions, as you're not mutating the container.
std::find_if returns(reference cppreference.com)
Iterator to the first element satisfying the condition or last if no
such element is found.
That means, dereference the iterator only when its not equal to container.end() iterator.
if (const auto iter = std::find_if(myvector.cbegin(), myvector.cend(), IsOdd); // need C++17 compiler support
iter != myvector.cend())
{
std::cout << *iter << "\n";
}
else
{
// code
}
PS: In modern C++, lambdas expressions should be your good friends, and use it when it is appropriate.
See more here: Why can lambdas be better optimized by the compiler than plain functions?
That means your IsOdd could have been
constexpr auto isOdd = [](const int i) /* noexcept */ { return i & 1; };

unordered_multimap - iterating the result of find() yields elements with different value

The multimap in C++ seems to work really odd, i would like to know why
#include <iostream>
#include <unordered_map>
using namespace std;
typedef unordered_multimap<char,int> MyMap;
int main(int argc, char **argv)
{
MyMap map;
map.insert(MyMap::value_type('a', 1));
map.insert(MyMap::value_type('b', 2));
map.insert(MyMap::value_type('c', 3));
map.insert(MyMap::value_type('d', 4));
map.insert(MyMap::value_type('a', 7));
map.insert(MyMap::value_type('b', 18));
for(auto it = map.begin(); it != map.end(); it++) {
cout << it->first << '\t';
cout << it->second << endl;
}
cout << "all values to a" << endl;
for(auto it = map.find('a'); it != map.end(); it++) {
cout << it->first << '\t' << it->second << endl;
}
}
this is the output:
c 3
d 4
a 1
a 7
b 2
b 18
all values to a
a 1
a 7
b 2
b 18
why does the output still contain anything with b as the key when I am explicitly asking for 'a'? Is this a compiler or stl bug?
find, as implemented, returns an iterator for the first element which matches the key in the multimap (as with any other map). You're likely looking for equal_range:
// Finds a range containing all elements whose key is k.
// pair<iterator, iterator> equal_range(const key_type& k)
auto its = map.equal_range('a');
for (auto it = its.first; it != its.second; ++it) {
cout << it->first << '\t' << it->second << endl;
}
That's not a bug, it is by design. find returns an iterator to one of the matching elements, that's all. You'll iterate to the end of the map with your construct.
You need to use multimap::equal_range to do what you are after.
There is an Example in www.cplusplus.com , about How to use equal_range method to get all elements having the same key.
// unordered_multimap::equal_range
#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>
typedef std::unordered_multimap<std::string,std::string> stringmap;
int main ()
{
stringmap myumm = {
{"orange","FL"},
{"strawberry","LA"},
{"strawberry","OK"},
{"pumpkin","NH"}
};
std::cout << "Entries with strawberry:";
auto range = myumm.equal_range("strawberry");
for_each (
range.first,
range.second,
[](stringmap::value_type& x){std::cout << " " << x.second;}
);
return 0;
}
Please reference the link : http://www.cplusplus.com/reference/unordered_map/unordered_multimap/equal_range/
It would seem that you get an iterator into the full "list" of pairs, starting at the first pair with 'a' as it's key. So when you iterate to the end, naturally you will get everything beyond 'a' as well. If you sought for 'c', you would probably iterate through the entire "list" doing what you do there. Perhaps you should iterate to "it != map.end() && it->first == 'a'" if you want all the a's.

How to see if a key is present in a map?

I hav two stl maps like map<int,int> and i want to compare them.. so here is the code..
map <int, int> a,b;
insert into a and b;
map<int,int>::iterator i;
for(i=a.begin();i!=a.end();i++){
if(what should be here?)
then cout << (*i).first << " also present in b" << endl;
}
I was hoping that something like (b[(*i).first]).exist??
Use map::find as:
for(i=a.begin(); i!=a.end(); i++)
{
if( b.find(i->first) != b.end() )
std::cout << (*i).first << " also present in b" << std::endl;
}
Note i->first and (*i).first are same.
Use map::find().
This will return true if i->first (the key of the element in a pointed by i) is present in b.
if (b.find(i->first) != b.end())
You can't use operator[], because that will create the key if it doesn't exist. Instead, use find:
map<int,int>::const_iterator it = b.find(a->first);
if( it == b.end() )
// NOT FOUND
std::map has a function named find for finding a key in the map. See this
So the code should be :
if( b.find( i->first ) != b.end() )
I like b.count(i->first) > 0.
map::find function
I will do as this :
std::map <int, int> a,b;
insert into a and b;
std::map<int,int>::iterator it = a.begin();
std::map<int,int>::iterator ite = a.end();
while (it != ite)
{
if (b.find(it->first) != b.end())
{
std::cout << it->first << " also present in b" << std::endl;
}
++it;
}
For your task for performance reasons I would suggest something like:
map<int,int>::iterator ia = a.begin(), ib = b.begin(),
iae = a.end() , ibe = b.end();
while(ia != iae && ib != ibe) {
if (ia->first < ib->first) ia++;
else if (ia->first > ib->first) ib++;
else {
cout << ia->first << " also present in b" << endl;
ia++; ib++;
}
}

Iterator loop in C++

I've been googling for this for so long but I couldn't get the answer. The most of sample that I found are based on iterating with vector, map and etc..
I have the code below.
multimap<int, int>::iterator it = myMuliMap.find(1);
Let's say I have three pairs that has key "1". I like to get those three pair from for loop.. I think that I can't use for(multimap::iterator anotherItr=myMuliMap.begin()..
The following code is in C#.. I like to get C++ version.. Thanks.
foreach(var mypair in it){
Console.WriteLine(mypair.Key);
}
The function you're looking for is equal_range. This returns an iterator to all pairs in the map which match the specified key
auto range = myMultiMap.equal_range(1);
for ( auto it = range.first; it != range.second; ++it) {
...
}
EDIT
Version without auto
pair<multimap<int,int>::const_iterator,multimap<int,int>::const_iterator>> it = myMultiMap.equal_range(1);
for ( multimap<int,int>::const_iterator it = range.first;
it != range.second;
++it) {
...
}
Use std::equal_range():
int tolookfor = 1;
typedef multimap<int, int>::iterator iterator;
std::pair<iterator, iterator> p =
std::equal_range(myMuliMap.begin(), myMuliMap.end(), tolookfor);
for (iterator it = p.first; it != p.second ++it)
std::cout << (*it).second << std::endl;
the multi_map's member function equal_range works similarily:
std::pair<iterator, iterator> p =
myMuliMap.equal_range(tolookfor);
This will print out only the values found by
std::pair<std::multimap<int, int>::iterator, std::multimap<int, int>::iterator> result;
result = myMultimap.equal_range(1);
for(std::multimap<int,int>::iterator it = result.first; it != result.second; it++)
{
std::cout << it->first << " = " << it->second << std:: endl;
}
You can use something like the following loop.
for (std::multimap<int, int>::iterator i = myMultiMap.lower_bound(1);
i != myMultiMap.upper_bound(1);
++i)
{
std::cout << i->first << " => " << i->second << '\n';
}
This is valid in the current version of C++.