Compare the Current And Next Element of A set - c++

I want to compare the current and next element of a set of addresses . I tried the following code
struct Address{
string state;
string city;
}
if((*it).state == (*(it+1)).state){
}
But the compiler gave an error that no match for operator+ in "it+1". On cplusplus.com I found that + operator is not supported for set containers. So I am unable to figure out a way to access both the current and the next element of a set in the same if statement.

But ++ is provided, so you can write:
?::iterator next = it;
next++;

Just create a copy of the iterator, advance it(++), then compare. Or, if your standard library has it, you can use the c++11 next function from the <iterator> library.
if(it->state == std::next(it)->state)

As you already found out the operator + is not supported for std::set iterators, since those are only bidirectional iterators and not random access iterators. So if you want to access the next element at the same time as the current one you have to make a copy and increment that one:
std::set<Address>::iterator next_it = it;
++next_it;
if(it->state == (next_it)->state)
If you are using c++11 this code can be simplyfied using the std::next function found in <iterator>(which basically does the same thing):
if(it->state == std::next(it)->state)
Of course writing that function is pretty trivial, so you could always write your own next when coding pre C++11 .
Also: Remember to make sure that the next iterator isn't equal to set.end()

Related

Input iterator can be read repeatedly while Output Iterator can only be written once?

I was reading The C++ Programming Language 4th edition by Bjarne Stroustrup. In the iterator chapter (Chapter 31.1.2), it says:
Input iterator: We can iterate forward using ++ and read each element (repeatedly) using *.
Output iterator: We can iterate forward using ++ and write an element once only using *.
I have done many searches on whether input iterator can be read only once or repeatedly, for example:
http://www.cplusplus.com/reference/iterator/InputIterator/
https://www.geeksforgeeks.org/input-iterators-in-cpp/
and most suggests that input iterator can be read once only. But why the author says repeatedly for the input iterator? Is this correct? And if so, why input iterator can be read repeatedly but output iterator can only be written once. I always thought input and output iterator are completely opposite of each other.
Thanks everyone!
The book is correct; and the contradicting sources are not. There appears to be no rule that disallows reading an object more than once by indirecting through an input iterator.
The other sources may be confused by another similar limitation which is that once input iterator has been incremented, all copies of the previous iterator are invalidated, and thus may not be indirected anymore. This limitation is shared by output iterators. By example:
value = *inputIt;
value = *inputIt; // OK
copyIt = inputIt;
++inputIt;
value = *copyIt; // Not OK
The book is also correct that output iterator does have the limitation:
*outputIt = value;
++outputIt;
*outputIt = value; // OK
*outputIt = value; // Not OK
I always thought input and output iterator are completely opposite of each other.
Many output iterators are also input iterators, so "opposite" isn't exactly very descriptive. They are partially overlapping sets of requirements. An iterator can meet both sets of requirements.
If we have *outputIt = 1; then *outputIt = 2; aren't we just assigning to the same *outputit twice?
Yes; And that's something that output iterators are not required to support.
Consider for example an output iterator that sends packets over the internet. You've written a packet, and it has been sent to the internet and received by some other machine. You can't travel back in time and decide that the packet that was sent is something different. You must move on to the next packet and send that instead.
Bjarne's quote is correct. If you have an input iterator you can do *iterator as many times as you want. If you have an output iterator you can only do *iterator once.
What they both have in common though is they can only be used in single pass algorithms. Once you increment either an input or output iterator then an iterator to a previous position is no longer required to be dereferenceable
That means in
while (iterator != end)
{
if (*iterator == some_value)
something = *iterator;
++iterator;
}
iterator has to be an input iterator since we dereference it twice each iteration. On the other hand
while (iterator != end)
{
something = *iterator;
++iterator;
}
works for both an input and output iterators since we do only a single dereference.
You can read through an input iterator as many times as you want to. That comes from the requirement that "(void)*a, *a is equivalent to *a" [input.iterators], see table.
You can only write through an output iterator once. For *r = o, "After this operation r is not required to be dereferenceable". [output.iterators], see table. After you increment r you have a new iterator, and you can again assign through it once.
Once you combine these two into a forward iterator, the restriction on multiple assignments through the same iterator goes away.

How to iterate an unordered_set from the end to the begin

I want to iterate an unordered_set from the end to the begin:
unordered_set<Expression*> BlocExpressions;
for(auto it=BlocExpressions.end(); it != BlocExpressions.begin(); it--)
{
//do some work
}
But there is no operator-- declared.
So, should I code the operator--, or is there a way to do that?
For std::unordered_set, the order in which you iterate through the elements does not matter. Saying that, you could just imagine the order is random. You get no particular order regardless you do a forward iteration or backward iteration. That's why it provides no reverse iterator nor provides the -- operator overload for normal iterator. Forward and backward iterations have the same semantics here: to iterate in a random order.
I can't understand why you use words "end" and "begin" for unordered_set. unordered_set does not have particular order. You can iterate all elements by using iterator object.
If you need order in the set, you should use other container, for example std::set
I also find it curious why there is no rbegin() and rend(). I am using unordered_set to add random numbers (unordered) to represent a certain path.
That would be great.
The solution I have found, it might help someone else is the following one. Adding the decrement in the first argument of the for loop:
auto it = --BlocExpressions.end()
unordered_set<Expression*> BlocExpressions;
for(auto it = --BlocExpressions.end(); ; it--){
//do some work
// This will include the last item (which is BlocExpressions.begin())
if(it == BlocExpressions.begin()){
break;
}
}

How to find the second to last element in a vector in C++?

I am trying to build a program that uses the second to last element in a vector, so far I've used:
(arr2.rbegin()+1)
If I use a comparison operator in a conditional such as:
if(arr2.rbegin()+1 == true)
I get an error message: no match for operator ==
Many of the answers and comments have the right idea but really ugly syntax. Here are two nice ways to express that.
arr2.end()[-2] // end() is past the last element, -1 for last element, -2 for second-last
arr2.rbegin()[1] // rbegin() is reverse order starting at 0 for last element, 1 for second-last
Demo: http://ideone.com/2cZeUq
It works because RandomAccessIterator, which vector has, is required to provide operator[] such that it[n] is equivalent to *(it + n), just like for pointers.
So the code in your question becomes just
if (arr2.rbegin()[1]) // test penultimate element
looking at the documentation here
http://www.cplusplus.com/reference/vector/vector/?kw=vector
I'd expect you to access your element by
secondToLast = myVector[myVector.size() - 2];
You can try doing like this:-
if(*(arr2.rbegin()+1))
Sometimes there might be less than 2 items in the list, so myVector.size() - 2 or other direct accessors will throw an error. I've done the following . . .
if (myVector.size() > 1)
{
secondToLast = myVector[myVector.size() - 2];
}
It depends on what you mean by "second to last element". Take the following iterator definition...
vector<int>::iterator it = arr2.end();
it--;
it--;
You have to decriment the iterator twice because when you declare the iterator to "point" to the end, it actually references the location AFTER the last element in the vector.
Dont forget that when you want the value that the iterator points to, you have to dereference it. like so...
cout << *it;
Mostly for lulz, but if your elements are non-scalar and you need to access a member of the element in question, you can use the ++-> construction:
std::vector<std::pair<int, int>> arr = ...;
auto grug = arr.rbegin()[1].first;
auto leet = arr.rbegin()++->first;
assert(grug == leet);
The way it works is we post-increment the iterator returned by rbegin() with ++ and then access it with ->. It is actually superior to the clearest [1] form in the sense it will work on any iterator, not only random access iterator.
Post it on review and get some popcorn.
There are many ways you can access elements from the back
one you can use is the back property that comes with std::vector container
and if you want to access an element from the back (either last element or up to n)
you can do this
std::vector vec{1,2,3};
int lastsecond = vec.back()-1; will give you -> 2;
you can check vector properties which there is a decent bit.
https://en.cppreference.com/w/cpp/container/vector

iterator for strings in array

i have the following situation
typedef std::array<std::array<string,9>,9>candidates;
std::vector<candidates>cand;
i need to traverse the strings in depths of recursion and want them unaltered even with re-sizing. how do i do it? the iterators i was using previously get invalidated on re-sizing i want a way around.. here's the previous attempt.
for(itr[d] = cand[d][i][j].begin(); itr[d] !=cand[d][i][j].end(); ++itr[d])
{
//if condition met - proceed to recursive call
//else reset (using ppp and push) and proceed to next element of string
}
Have you tried
func(*(itr[d]));
The dereference operator takes precedence over the indexing operator.

Erase final member of std::set

How can I delete the last member from a set?
For example:
set<int> setInt;
setInt.insert(1);
setInt.insert(4);
setInt.insert(3);
setInt.insert(2);
How can I delete 4 from setInt? I tried something like:
setInt.erase(setInt.rbegin());
but I received an error.
in C++11
setInt.erase(std::prev(setInt.end()));
You can decide how you want to handle cases where the set is empty.
if (!setInt.empty()) {
std::set<int>::iterator it = setInt.end();
--it;
setInt.erase(it);
}
By the way, if you're doing this a lot (adding things to a set in arbitrary order and then removing the top element), you could also take a look at std::priority_queue, see whether that suits your usage.
Edit: You should use std::prev as shown in Benjamin's better answer instead of the older style suggested in this answer.
I'd propose using a different name for rbegin which has a proper type:
setInt.erase(--setInt.end());
Assuming you checked that setInt is not empty!
Btw. this works because you can call the mutating decrement operator on a temporary (of type std::set<int>::iterator). This temporary will then be passed to the erase function.
A bit less performant, but an alternative option:
setInt.erase(*setInt.rbegin());
If you want to delete 4 instead of the last you should use the find method.
Depending on the use case 4 might not be the last.
std::set<int>::iterator it = setInt.find(4);
if(it != setInt.end()) {
setInt.erase(it);
}
If you want to delete the last element use:
if (!setInt.empty()) {
setInt.erase(--setInt.rbegin().base());
// line above is equal to
// setInt.erase(--setInt.end());
}
While I was not sure if --*.end(); is O.K. I did some reading.
So the -- on rbegin().base() leads to the same result as -- on end().
And both should work.
Check if the set is empty or not. If not, then get the last element and set that as iterator and reduce that iterator and erase the last element.
if (!setInt.empty())
{
std::set<int>::iterator it = setInt.end();
--it;
if(it != setInt.end()) {
setInt.erase(it);
}
}