How to see if a key is present in a map? - c++

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++;
}
}

Related

finding all the values with given key for multimap

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

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 iterate through a set of sets C++

Pretty new to C++, only at it a week or so, I want to iterate through a set of nested sets and write each element in the inner set to a line in a file.
Each inner set has 3 elements and I want all three elements on the same line.
I have a set up as follows:
// Define "bigSet" and initiate as empty set "Triplets"
typedef set < set<string> > bigSet;
bigSet Triplets;
I tried something of this sort to go through it but it gives me an error...
// Iterate through and print output
set <string>::iterator it;
for(it = Triplets.begin(); it != Triplets.end(); it++){
cout << *it << endl;
}
Any help is greatly appreciated guys thank you!
I would do it this way:
// Iterate through and print output
set < set <string> >::iterator it_ex; // iterator for the "outer" structure
set <string>::iterator it_in; // iterator for the "inner" structure
for(it_ex = Triplets.begin(); it_ex != Triplets.end(); it_ex++)
{
for(it_in = it_ex->begin(); it_in != it_ex->end(); it_in++)
cout << *it_in << ", ";
cout << endl;
}
Triplets is not a set<string>; it is a set<set<string>>; each item in Triplets is itself a set, than can contain several strings.
The iterator must match the type of the container; with two levels of nested containers, you should iterate twice:
set<set<string>>::iterator it;
set<string>::iterator it2;
for(it = Triplets.begin(); it != Triplets.end(); it++) {
for (it2 = it->begin(); it2 != it->end(); ++it2) {
cout << *it2 << endl;
}
}
Triplets is type set < set<string> > and therefore requires an iterator of type set < set<string> >::iterator or bigSet::iterator. It isn't type set <string>. You could also use const_iterator.
Note that iterating Triplets gives you an iterator to another set, and not a string.
Also consider
for (const auto& i : Triplets)
{
for (const auto& j : i)
{
cout << j << endl;
}
}
You have an error because Triplets.begin() is not of type set<string>::iterator, it's set<set<string>>::iterator.
What you need to do is have two loops: one for iterating over the outer set and one for the inner.
set<set<string>>::iterator it;
for(it = Triplets.begin(); it != Triplets.end(); ++it)
{
set<string>::iterator it2;
for(it2 = it->begin(); it2 != it->end(); ++it2)
{
cout << *it2;
}
cout << endl;
}
If you use increment/decrement operators (++/--) on iterators, it might be better to use the prefix versions (++it) instead of the suffix ones (it++). This is because the suffix ones create a copy of the iterator before it is incremented (and that copy is then returned) but in cases like this, you have no need for it.
Moreover, if you're using C++11, you can use the range-based for loops and auto keyword, which simplify things a lot:
for(const auto &innerSet : Triplets)
{
for(const auto &innerSetElement : innerSet)
{
cout << innerSetElement;
}
cout << endl;
}
First: if they're triplets, are you sure that std::set is the type you
want for the inner values. Perhaps a class would be more
appropriate, in which case, you define an operator<< for the `class,
and your simple loop works perfectly. Something like:
class Triplet
{
std::string x;
std::string y;
std::string z;
public:
// Constructors to enforce that none of the entries are identical...
// Accessors, etc.
friend std::ostream& operator<<( std::ostream& dest, Triplet )
{
dest << x << ", " << y << ", " << z;
return dest;
}
};
And then to output:
for ( Triplet const& elem : Triplets ) {
std::cout << elem << std::endl;
}
Otherwise: you need to define the format you want for the output. In
particular, you'll probably want a separator between the strings in the
line, for example. Which means you probably cannot use a range based
for, at least not for the inner loop. You would need something like:
for ( std::set<std::string> const& triplet : Triplets ) {
for ( auto it = triplet.cbegin(); it != triplet.cend(); ++it ) {
if ( it != triplet.cebegin() ) {
std::cout << ", ";
}
std::cout << *it;
}
std::cout << std::endl;
}
(If the set of triplets is large, you'll definitely want to consider
replacing std::endl with '\n'. But of course, if it is really
large, you probably won't be outputting to std::cout.)

Adding elements into a c++ map

I have a map in my program that stores the code of a Product p and the amount of it.
If a ask for a new request, and if the product already exists in the map, i just need to sum the second element of the pair(code, amount) to the element in the map.
How can I do this?
void Request :: addItem (Product p, double amount) {
if(this->isItemRequest(p)) {
//p already exists in the map.
}
this->rdata.insert(pair<int, double>((int)p.getCode(), amount));
}
Thanks a lot!
Assuming your map is declared within the Request class as std::map<int, double> rdata, the code can be:
void Request::addItem( Product p, double amount )
{
if ( this->isItemRequest(p) )
{
int Code = int(p.getCode);
this->rdata[ Code ] += amount;
}
this->rdata.insert( pair<int, double>(int(p.getCode), amount) );
}
However, if isItemRequest() is just a trivial check, your code can be simplified to just:
void Request::addItem( Product p, double amount )
{
int Code = int(p.getCode);
this->rdata[ Code ] += amount;
}
P.S. Maybe, it is a good idea (if you can change the interface) to pass Product by const reference.
If you call on:
this->rdata[key] = value;
you create a value using default constructor (int() initializes to 0), return reference to it, and call operator= on it. You can avoid that by checking if key exist first:
this->rdata.count(key) != 0
or simplier
this->rdata.count(key)
if it exists you can use operatror=, operator+= and so on on reference returned by operator[]:
if (this->rdata.count(key) == 0)
this->rdata.insert( pair<int, double>( key, value ) );
else
this->rdata[key] += value;
but in this simple case
this->rdata[key] += value;
should just do.
The simplest way to do that is
rdata[p.getCode()] += amount;
If it wasn't already in the map, then [] will insert an element with value zero, so the value will end up being amount. If it was, then amount is added to the existing value.
Easy: map.find :)
#include <iostream>
#include <map>
#include <string>
typedef std::map<std::string, int> StringIntMap;
int main() {
StringIntMap map;
map["coke"] = 10;
map["fries"] = 25;
map["pizza"] = 50;
std::cout << "Before increase" << std::endl;
StringIntMap::const_iterator it;
for (it = map.begin(); it != map.end(); it++) {
std::cout << it->first << ": " << it->second << std::endl;
}
std::cout << "Now, increase pizza +50" << std::endl;
StringIntMap::iterator item = map.find("pizza");
if (item != map.end()) {
// pizza exists increase 50
item->second += 50;
} else {
std::cout << "Sorry, no pizza here" << std::endl;
}
std::cout << "after increase" << std::endl;
for (it = map.begin(); it != map.end(); it++) {
std::cout << it->first << ": " << it->second << std::endl;
}
return 0;
}

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++.