how to iteratively print the elements in a SET (STL) - c++

This is the code I have. It is correct.
set<float> set1;
set1.insert(1);
set1.insert(2);
set1.insert(3);
set<float>::iterator it1;
for (it1 = set1.begin(); it1 != set1.end(); it1 ++)
{
cout << *it1 <<" ";
}
But why doesn't the following code work?
set<float> set1;
set1.insert(1);
set1.insert(2);
set1.insert(3);
set<float>::iterator it1;
for (it1 = set1.begin(); it1 != set1.end()-1; it1 ++)
{
cout << *it1 <<" ";
}

The iterators of an std::set are bidirectional. That means they support single steps in either direction (it++, it-- etc), but do not support increments of arbitrary length (it + N etc).
This is likely because it would be an inefficient O(N) operation, given that std::set is usually implemented as a self balancing binary search tree.
You can increment/decrement a bidirectional iterator by an arbitrary amount by using std::advance, std::next or std::prev:
std::advance(it, 42);
it = std::next(it, 42);
it = std::prev(it, 42);

operator- and operator+ is not supported for set iterators which are not of random access type, but are bidirectional type.
Ref : Here

The iterator type returned by set<>::begin() has no operator+(int) specified. However, in your example you can use the operator--() instead:
for (it1 = set1.begin(); it1 != --set1.end(); ++it1)
{
cout << *it1 << " ";
}

Related

Looking for a string in two iterators in C++

In C++, I am aware that you can have multiple iterators. For example, if you had a function that wanted to see the first concurrence of a string in two iterators why would a code look something like this:
Iterator found_it(Iterator one, Iterator two){
while(one != two && (*one) != "Bob"){
one++;
}
return one;
}
*The question said one and two don't necessarily mean begin() and end() - that is what really gave me a mind**** and confusion :S*
Firstly, what happens if Bob was in iterator two? Because you are only returning iterator one? This is what is really confusing me at the moment.
Thanks
When two iterators used as a range for a function or a standard algorithm then the second iterator is not included in the range. That is you should consider the range like
[first, last )
If a function or algorithm like std::find returns the second iterator then it means that the range does not contain the target value.
If the second iterator was included in the range then a question arises what iterator to return when the target value is not found?
Consider for example your own function with the following its calls
template <class Iterator>
Iterator found_it(Iterator one, Iterator two){
while(one != two && (*one) != "Bob"){
one++;
}
return one;
}
//...
std::vector<std::string> v1 = { "Mary", "Bob" };
std::vector<std::string> v2 = { "Mary", "Peter" };
auto it1 = found_it( v1.begin(), v1.end() );
if ( it1 != v1.end() ) std::cout << *it1 << " is present in v1" << std::endl;
else std::cout << "Bob" << " is not present in v1" << std::endl;
auto it2 = found_it( v2.begin(), v2.end() );
if ( it2 != v2.end() ) std::cout << *it2 << " is present in v2" << std::endl;
else std::cout << "Bob" << " is not present in v2" << std::endl;
one and two are the beginning and end (really just beyond the end) of the range that you want to search. This might not be the same as begin() and end() on a container, if you wanted to search only a subrange, or if the iterators don't come from a container at all.
Note that one is changed within the loop; you're not necessarily returning the original value of one.
Your function could be rewritten equivalently like this:
Iterator found_it(Iterator begin, Iterator end) {
Iterator current = begin;
while (current != end && (*current) != "Bob"){
current++;
}
return current;
}
If "Bob" is at iterator two then it is out of the range you wish to search so it should not be found. The second iterator is one past the search range.
So you search from one up to, but not including, two.
When you want to search an entire container then you will pass begin() and end() as arguments to one and two. But iterators give you the flexibility to search for intermediate ranges within a container.
For example what if you want to find all the Bobs?
std::vector<std::string> names {"Tim", "Beryl", "Bob", "Danny", "Bob", "Lou"};
You can get the first one like this:
auto bob1 = fond_it(names.begin(), names.end());
You can get the second one like this:
auto bob2 = fond_it(bob1 + 1, names.end());
Notice you can start the search half way through using bob1 rather than at the beginning.

Increment an iterator standard map

ALL,
std::map<int, std::string> addressee;
std::map<int, std::string>::iterator it1, it2;
for( it1 = addressee.begin(); it1 != addressee().end(); it1++ )
{
bool found = false;
for( it2 = it1 + 1; it2 != addressee.end() && !found; it2++ )
{
if( it1->second == it1->second )
{
printf( "Multiple occurences of addressees found" );
found = true;
}
}
}
gcc spits out an error: no match for operator+.
This code is a simplified version of what I'm trying to do right now. I guess I can use std::advance(), but it seems it just going to be a waste of the function call.
Is there a better fix for that?
std::map does not have random access iterators, only bidirectional iterators, so there's no + n operation. Instead, use std::next:
#include <iterator>
#include <map>
// ...
for (auto it1 = addressee.begin(), e = addressee.end(); it1 != e; ++it1)
{
for (auto it2 = std::next(it1); it2 != e; ++it2)
{
if (it1->second == it2->second)
{
// ...
break;
}
}
}
In fact, you should always use std::next, since it knows which iterator category its argument has and what the most efficient way to compute the next iterator is. That way, you don't have to care about the specific container you happen to be using.
#Kerrek has already pointed out how to handle the problem you're having at the syntactic level.
I'm going to consider the problem at a more algorithmic level--what you're really trying to accomplish overall, rather than just looking at how to repair that particular line of the code.
Unless the collection involved is dependably tiny so the efficiency of this operation doesn't matter at all, I'd make a copy of the mapped values from the collection, then use sort and unique on it to see if there are any duplicates:
std::vector<std::string> temp;
std::transform(addressee.begin(), addressee.end(),
std::back_inserter(temp),
[](std::pair<int, std::string> const &in) { return in.second; });
std::sort(temp.begin(), temp.end());
if (std::unique(temp.begin(), temp.end()) != temp.end()) {
std::cout << "Multiple occurrences of addressees found";
found = true;
}
This reduces the complexity from O(N2) to O(N log N), which will typically be quite substantial if the collection is large at all.

a small issue with std::vector and changing the collection while looping through it

This loop changes the iterators while running:
std::vector<int> c;
c.push_back(1);
c.push_back(2);
std::vector<int>::iterator iter = c.begin();
std::vector<int>::iterator endIter = c.end();
while( iter != endIter )
{
std::cout << (*iter) << std::endl;
iter = c.erase(iter);
}
It does not work because:
Iterators and references to the erased elements and to the elements between them and the end of the container are invalidated. Past-the-end iterator is also invalidated
How can I rewrite this (without using std::list, and using the while loop) ?
By the way, I know that auto has been implemented since C++11. Why would it be beneficial to use it ?
Simply do not cache the end iterator that will be invalidated:
while( iter != c.end() )
{
std::cout << (*iter) << std::endl;
iter = c.erase(iter);
}
or clear the vector after printing:
for(const auto& i : c) {
std::cout << i << std::endl;
}
c.clear();
Erasing an element changes end(). Change the loop:
while( iter != c.end())
Either
Rewrite it as
while( iter != c.end() )
{
std::cout << (*iter) << std::endl;
iter = c.erase(iter);
}
and the code will no longer rely on any potentially invalidated iterators,
or
"Refresh" any potentially invalidated iterators after each invalidating operation
while( iter != endIter )
{
std::cout << (*iter) << std::endl;
iter = c.erase(iter);
endIter = c.end();
}
These are the two generic approaches typically used in cases like that.
A more idiomatic way of doing this...
while(c.begin() != c.end()) c.erase(c.begin());
Though this is very slow, as a vectors underlying implementation uses a contiguous array(with extra space on the end). So repeatedly erasing the begin element is very ineficient, as every element ends up getting copied one space in the array earlier, n - index times! You can jurastically increase performance by doing this:
while(c.begin() != c.end()) c.pop_back();

vector iterators c++

I am a little confused by the way begin and end work they seem to me to be inconsistant. When going forward and backwards they have different behaviors.
vector<Actor *> a;
a.push_back(new Actor(11));
a.push_back(new Actor(22));
a.push_back(new Actor(33));
vector<Actor *>::iterator it = a.begin();
int x =0;
while(a.begin()+x != a.end()){
cout << (*(a.begin()+x)) << "\n";
x++;
}
cout << "\n";
int y = 1; // if this is set to 0 then its a seg fault =/ when I access
while(a.end()-y != a.begin()){
cout << (*(a.end()-y)) << "\n";
y++;
}
Outputs
0x979a008
0x979a028
0x979a018
0
0x979a018
0x979a028
How can I get the expected pattern
0x979a008
0x979a028
0x979a018
0x979a018
0x979a028
0x979a008
Note that begin() points to the first element of the vector, but end() points past the last element. It's never safe to dereference end(), but you can compare iterators to it.
If the vector is empty, then begin() == end(), and you may not dereference either one.
A more idiomatic way to loop over a vector's elements is:
for (vector<Actor*>::iterator i = a.begin(); i != a.end(); ++i) {
// do something here
}
To iterate in reverse, it's simpler to use rbegin() and rend(), which work much the same way and begin()/end(), but iterate in reverse order:
for (vector<Actor*>::reverse_iterator i = a.rbegin(); i != a.rend(); ++i) {
// do something here
}
Also, if you don't intend to modify the elements, you should use a const_iterator (or const_reverse_iterator instead.
You should use reverse iterators:
int y = 0;
while(a.rbegin() +y != a.rend()){
cout << (*(a.rbegin()+y)) << "\n";
y++;
}
Or even better would be to use the overloaded ++ operator of the iterators themselves:
auto iter = a.rbegin();
while(iter != a.rend()){
cout << *(iter++) << "\n";
}
One very simple way to achieve that would be following
// first element to the last
auto it = a.begin()
while (it != a.end())
{
cout<<*it<<"\n";
++it;
}
cout<<"\n"
// Last element to first
auto rit = a.rbegin()
while(rit != a.rend())
{
cout<<*rit<<"\n";
++rit;
}
NB: Do not try to dereference a.end() and beyond. When y = 0 in your program the a.end() is dereferenced in the line cout << (*(a.end()-y)) << "\n"; This results in seg fault.
Elements of vector are contained in a sequence which can be accessed from begin() through end()-1. .end() points to one "past" the last element of the container and should not be dereferenced.
std::for_each(a.begin(), a.end(), [](const Actor *& a){ std::cout << a; });
std::for_each(a.rbegin(), a.rend(), [](const Actor *& a){ std::cout << a; });
auto print_actor = [](const Actor *& a){ std::cout << a; };
std::for_each(a.begin(), a.end(), print_actor);
std::for_each(a.rbegin(), a.rend(), print_actor);

How to get unique pairs of values from a stl set

I have a stl set of integers and I would like to iterate through all unique pairs of integer values, where by uniqueness I consider val1,val2 and val2,val1 to be the same and I should only see that combination once.
I have written this in python where I use the index of a list (clusters):
for i in range(len(clusters) - 1):
for j in range(i+1,len(clusters)):
#Do something with clusters[i],clusters[j])
but without an index I am not sure how I can achieve the same thing with a stl set and iterators. I tried out:
for (set<int>::iterator itr = myset.begin(); itr != myset.end()-1; ++itr) {
cout << *itr;
}
but this fails as an iterator doesn't have a - operator.
How can I achieve this, or must I use a different container?
How about something along the following lines:
for(set<int>::const_iterator iter1 = myset.begin(); iter1 != myset.end(); ++iter1) {
for(set<int>::const_iterator iter2 = iter1; ++iter2 != myset.end();) {
{
std::cout << *iter1 << " " << *iter2 << "\n";
}
}
This yields all N*(N-1)/2 unique pairs, where N is the number of integers in your set.
As an aside: use a const_iterator whenever you iterate over a container without modifying anything, it's good style and might have better performance.
EDIT: Modified the code to reflect the suggestion made by Steve Jessop.
You don't need to do end() - 1 since end() is an iterator that points after the last element in the container.
The corrected code is:
for (set<int>::iterator itr = myset.begin(); itr != myset.end(); ++itr) {
for (set<int>::iterator itr2 = itr + 1; itr2 != myset.end(); ++itr2) {
// Do whatever you want with itr and itr2
}
}
Put your data in a boost::bimap, then iterate it both ways, copying the results into a standard STL map which will enforce uniqueness.