How to endlessly loop over map - c++

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

Related

Map iterator no match for operator

I have no match for operator in map iterator. When I try to make the iterator it points to the map end-1.
#include <iostream>
#include <map>
int main()
{
std::map<char,int> mymap;
mymap['b'] = 100;
mymap['a'] = 200;
mymap['c'] = 300;
// show content:
for (std::map<char,int>::iterator it=mymap.begin(); it!=mymap.end()-1; ++it){
std::cout << it->first << " => " << it->second << '\n';
}
return 0;
}
This statement
mymap.end()-1
is only legal for Random Access Iterator but std::map::iterator is Bidirectional Iterator. If you want to skip last element use std::prev()
for (std::map<char,int>::iterator it=mymap.begin(); it!=std::prev( mymap.end() ); ++it)
though it is not efficient to always calculate it and it should be instead:
auto end = std::prev( mymap.end() );
for (auto it=mymap.begin(); it!=end; ++it) ...
Note for this to work you have to be sure that there is at least one element in your map. If you do not want to skip the last element remove -1 completely.
There's no operator- for map iterators, but it doesn't matter because if you want to show all the content is should be just it!=mymap.end();

Remove an entry out of a std::list while iterator

I am trying to remove elements in a list when a condition is met in a std::list. What I have read in the Reference about the return value of the erase function:
An iterator pointing to the element that followed the last element
erased by the function call. This is the container end if the
operation erased the last element in the sequence.
Member type iterator is a bidirectional iterator type that points to
elements.
I have put this example together:
#include <string>
#include <list>
#include <iostream>
int main()
{
typedef std::list<std::string> string_list_t;
string_list_t list;
list.push_back("test1");
list.push_back("test2");
list.push_back("test3");
list.push_back("test4");
list.push_back("test5");
list.push_back("test6");
list.push_back("test7");
list.push_back("test8");
for (string_list_t::iterator it = list.begin(); it != list.end(); ++it)
{
std::string &str = *it;
std::cout << "Checking " << str << "..." << std::endl;
if (str == "test4")
{
std::cout << "Found test4!" << std::endl;
}
else
{
it = list.erase(it);
}
}
return 0;
}
It does not give me the expected output, instead it gives me:
Checking test1...
Checking test3...
Checking test5...
Checking test7...
Can someone help me figuring out what I understood wrong? Somehow it skips every second element...
You are skipping the element after the deleted one.
You should use either it = list.erase(it); or ++it, but not both.
When you erase an element from a std::list, do not increment the iterator returned by the std::list::erase method. You will not just skip the next element, you may just end up incrementing an end() iterator.
Change your loop to:
for (string_list_t::iterator it = list.begin(); it != list.end(); )
//^^ Not incremented
{
std::string &str = *it;
std::cout << "Checking " << str << "..." << std::endl;
if (str == "test4")
{
std::cout << "Found test4!" << std::endl;
++it; //increment
}
else
{
it = list.erase(it);
}
}
See it Live Here

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

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