string erase appends elements with backward iterators - c++

I am trying to remove every '0' in a std::string, starting from the back. According to this, there are multiple ways to .erase backward iterators.
The weird thing is that they all append numbers to the std::string, instead of erasing them!
Here is a little sample
//'str' will be "5.090000"
std::string str = std::to_string(5.09);
auto it = std::remove_if(str.rbegin(), str.rend(), [](char value) {
return value == '0';
});
1) Pre-C++11 way:
str.erase(--(it.base()));
2) C++11 way (1)
str.erase(std::next(it).base());
3) C++11 way (2)
std::advance(it, 1);
str.erase(it.base());
In all cases, str == "5.095.9". Why? Because as I see it, str should be 5.9, but it isn't...
My best guess is that I am doing something wrong with the backwards iterators, because if you split the string: 5.09 | 5.9, the first value has still the in-between '0', but not the last ones. The second value is actually the std::string I expected.
What I am doing wrong?

I made 2 errors in my approach:
erase called with only 1 iterator removes the element the iterator is pointing at, not from the iterator to the end (as I falsely assumed)
So str.erase(std::next(it).base(), str.end()); - this is still wrong, continue reading ;)
As #KerrekSB pointed out, I didn't read the docs carefully enough: Because I am using std::reverse_iterator, the elements get pushed back to the front! So, as it points to the new end iterator (which is BTW before the not-removed elements), I have to delete the range from the beginning (str.begin()) to it.base().
TL;DR
The new working version is: str.erase(str.begin(), it.base());

Related

How to get position of a certain element in strings vector, to use it as an index in ints vector? (= original name of thread)

because of not enough reputation I can't comment a post on the the thread:
How to get position of a certain element in strings vector, to use it as an index in ints vector?
I want to know something regarding this answer:
Original answer on thread:
To get a position of an element in a vector knowing an iterator pointing to the element, simply subtract v.begin() from the iterator:
ptrdiff_t pos = find(Names.begin(), Names.end(), old_name_) - Names.begin();
Now you need to check pos against Names.size() to see if it is out of bounds or not:
if(pos >= Names.size()) {
//old_name_ not found
}
vector iterators behave in ways similar to array pointers; most of what you know about pointer arithmetic can be applied to vector iterators as well.
Starting with C++11 you can use std::distance in place of subtraction for both iterators and pointers:
ptrdiff_t pos = distance(Names.begin(), find(Names.begin(), Names.end(), old_name_));
Questions:
How does this exactly work for the compiler? What happens in the background?
I know, that im passing two iterators to the find method, which seems logic: I pass the start and the end position. In between, I'm searching for the element. std::find() returns an iterator of the first element satisfying the value passed as third parameter to the std::find() method. So is std::distance doing nothing else than incrementing in a for loop something like a counter until it reaches the "end-point" iterator?
I could also write:
int index = distance(Names.begin(), find(Names.begin(), Names.end(), old_name_));
Why is it better to use ptrdiff_t than an integer? Someone commented in the original post that it lets you store the distance between any pair of iterators into the same container, even in situations when the result is negative. But I do not really get the point of it. Maybe you could explain that a bit further. (:
I'm coming from C#, where you can use something like (demonstrated on a string):
string test = "Hello World";
int index = test.IndexOf("d");
This seems a lot easier compared to the methods used above in C++. Is there something equivalent in C++?
Thank you very much for your help!
Best regards

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

Delete recurring characters

For a little something I was trying out in C++, I have accepted a string (say 'a tomato is red') and gotten rid of spaces ('atomatoisred').
Now how would I go about deleting recurring characters only, on condition that the first instance of that character gets to stay (so our example becomes,'atomisred')?
Thanks in advance!
You can use the erase-remove idiom in conjunction with a set keeping track of the duplicate characters:
std::set<char> dupes;
str.erase(
std::remove_if(
str.begin(), str.end(),
[&](char c) { return not dupes.insert(c).second; }),
str.end());
This also uses the fact that the return value of std::set::insert is a pair whose second element is a bool indicating whether the insertion took place.
If you want to implement it yourself (without stl), there are a number of ways.
Through sorting. This works if you don't care about the order of the chars. Sort your string first, then go through it, performing a very simple check on every element:
if( currentElement == elemebtBeforeIt )
deleteCurrentElement
Another way is to have an array dedicated to the unique characters (well, maybe not an array, but you'll get the idea). Go through your string, and for each charcter, check:
foreach Element of the string:
if( arrayOfUniqueElements contains currentElement )
do nothing
else
put currentElement into the arrayOfUniquElements
After this, you will have all unique elements in the dedicated array.

How to get the end of a vector and assign it to a string

I want to get the last element of the vector and then assign it to a string but I seem to have problems.
Imagine this vector has already been filled but I do not know how much so I tried to do this.
std::vector<std::string> vec;
std::string s = vec.end();
Would a loop work and then just get the last index ?
This did not work so is there a way to get the end of a vector?
EDIT------
out.push_back(r.validateR(str));
appendCustomizedOutput = out.back();
DCS_LOG_DEBUG("END " << appendCustomizedOutput);
split(test,appendCustomizedOutput,boost::is_any_of("\n"));
DCS_LOG_DEBUG("END " << test[0]);
When i try to print test[0] nothing is printed and i do not know why ?
vector::end() returns an iterator that is one beyond the last real element in the vector (it's used primarily for checking while iterating).
Best way would be:
std::string s = vec.back(); // last item
As #JamesKanze and #PeterWood says, don't forget to check for empty vector - else it's undefined behaviour...
That's what vec.back() is for. Just make sure that the vector isn't empty first.
Use vec.back()to get a reference to the last element. Use vec.pop_back()to remove the last element (without returning it).
container.end() (or whatever kind of container) will return an iterator to the end of the container. To get the last item in the container, you want container.back() instead:
std::string s = vec.back();
end() returns an iterator referring to the past-the-end element in the vector container.
You need back(): it returns a reference to the last element in the vector container.

Compare the Current And Next Element of A set

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