How can I remove only the last occurrence of a value in a C++ vector?
I have this pice of code.
if(vect.erase(std::remove(vect.begin(), vect.end(), oldVal),vect.end()) == vect.end()){
cont++;
}
vect.push_back(newVal);
It removes all instances of a value in the array. I need it to remove only the last specific element in the vector.
Example
Vector: 1 3 4 5 3 5 3 8 3 6
End I want to remove a '3' then should get:
1 3 4 5 3 5 3 8 6
Is there any canonical solution or should I try a stack os list?
std::find will find an element
std::reverse_iterator, accessed by myVector.rbegin() allows you to search from the back.
erase() as above.
Something like:
auto foundIt = std::find(vect.rbegin(), vect.rend(), oldVal);
// Find first from the back, i.e. last
if (foundIt != vect.rend()) { // if it was found
// get back to the right iterator
auto toRemove = --(foundIt.base());
// and erase it
vect.erase(toRemove);
}
Related
I was lately trying to access every 2nd last element from a multiset container. Here I want to first print every 2nd last element from the container then erase it from the container. This process continues until the size of the container reaches to 1.
My so far approach for this process is given bellow-
int n;cin>>n;
multiset<int>st;
for(int i=0;i<n;++i)
{
int x;cin>>x;st.insert(x);
}
while(st.size()!=1)
{
auto it=st.rbegin();
prev(it,1);
cout<<*it<<" ";
st.erase(*it);
}
Here, my expected results for the given case is-
6
0 0 1 0 1 1
ans- 1 1 0 0 0
Thanks in advance.
Find the answer of the question .Here as I am using multiset I accidently erasing all copies of (*it).So I just need to find the value first then erase from the set.
st.erase(find(*it))
I created 5 numbers using vector with SFML, but I want the second one to fall one by one at intervals of 1 second. But, they first three falling as one by one. I don't understand why something like this is happening. Can you help me?
if (second == 1)
{
random.at(2)-=1;
cout << random[2] << endl;
text.setString(to_string(random[2]));
text.setPosition(numbers[2].getPosition().x, numbers[2].getPosition().y);
numbers.push_back(text);
numbers.erase(numbers.begin() + 2);
clock.restart();
}
The program gif
Full code
I'll give you a hand.
Here's what's happening:
You create 5 numbers in the random array. You may not have noticed it, but they are numbered 0 to 4 (SFML is sitting on C++, and then it means that arrays starts at zero here).
Every second, you update the number stocked in the 3rd place of your random array.
Then it goes wrong: instead of updating the corresponding number in the numbers array, you cycle it with push_back and erase.
Understand me here: push_back create a new element at the end of the vector, while erase removes an element from the vector and then "sort out things" so there's not number gap in the index of the vector.
Effectively, you're handling random right, but when you try to update number you cycle through it. Like this:
seconds: 1 2 3 4 5 6
array content: 0 0 0 0 0 0
(vertical) 1 1 1 1 1 1
2 3 4 5 6 7
3 4 5 6 7 8
4 5 6 7 8 9
I'm not sure how clear I'm making this, but if you look at the array content, you'll see that by erasing and creating a new value at the end, you're cycling through the positions [2-4] of the array. That's why in your gif not all numbers are updated wrong, only 3 of them.
The obvious solutions would be to stop erasing and pushing back in the numbers array. You can update it the same way you updated the random array. It'll be fine.
Like this:
if (second == 1)
{
random.at(2)-=1;
cout << random[2] << endl;
numbers[2].setString(to_string(random[2]));
clock.restart();
}
Have fun.
How does the unique and resize maintain that no repetition occurs:
for(map <string, vector<int> >::iterator it = m.begin(); it != m.end(); ++it)
{
vector<int>::iterator sz = unique((it->second).begin(),(it->second).end());
(it->second).resize(distance((it->second).begin(),sz));
}
The vector is sorted.
So basically the question is about reading documentation.
std::unique() pulls elements to the back of the vector, and returns an iterator to the first non unique element.
In the beginning sequence may look like: 1 1 2 2 2 3 6 6
After the call to unique the sequence changes to: 1 2 3 6 ...(duplicated).
Then distance() calculates how many unique elements are, which is distance from first unique element to first non unique element. .resize() just cuts off non unique part.
.erase(sz, (it->second).end); would be better to use in this case. Also the loop itself is rather weird.
this loop works fine as expected. however is there any STL approach to mimic the exact functionality as the example below?
for (auto i = vec.size() - 1; i > 0; --i)
{
vec[i] = vec[i - 1];
}
Rather than an insertion or a rotate, all we're doing here is copying, so it seems like the thing to use is a copy. We could do the job with reverse_iterators:
std::copy(f.rbegin() + 1, f.rend(), f.rbegin());
...or with the algorithm really intended specifically for this sort of situation, std::copy_backward:
std::copy_backward(f.begin(), f.end()-1, f.end());
Either way, it's simple, straightforward, and about as efficient as possible (almost certainly more efficient than using insert/pop or rotate/assign).
std::rotate:
template< class ForwardIt >
ForwardIt rotate( ForwardIt first, ForwardIt n_first, ForwardIt last );
Used as (for a vector v)
// rotation left
std::rotate(v.begin(), v.begin() + 1, v.end());
// example:
// initial v: 1 2 3 4 5
// after rotate: : 2 3 4 5 1
// rotation right (as in your "script")
std::rotate(v.rbegin(), v.rbegin() + 1, v.rend());
// example:
// initial v: 1 2 3 4 5
// after rotate: 5 1 2 3 4
//now if you do this,then it'll have the same effect as your code.
v[0] = v[1];
//before assignment: 5 1 2 3 4
//after assignment: 1 1 2 3 4
The difference w.r.t. your example is that, here, the first element will receive the previously last element (whereas in your code, the first element is untouched).
Performs a left rotation on a range of elements.
Specifically, std::rotate swaps the elements in the range [first,
last) in such a way that the element n_first becomes the first element
of the new range and n_first - 1 becomes the last element.
A precondition of this function is that [first, n_first) and [n_first,
last) are valid ranges.
http://en.cppreference.com/w/cpp/algorithm/rotate
The exact equivalent? Assuming the vector is not empty:
auto val = vec.front(); //Just in case the list is 1 element long.
vec.pop_back();
vec.insert(vec.begin(), val);
Your code effectively does this:
1 2 3 4 5 6
1 1 2 3 4 5
The first element is in two places, while the last element is lost. The above code does the same.
for(myIterator = numbers.begin();myIterator != numbers.end() ;myIterator++)
{
resultVect.push_back(*myIterator+2);
numbers.erase(myIterator+2);
}
numbers consist of a series of numbers (eg 1,2,3,4,5,6,7)
Then I would like to erase every 3rd number.
Something like,
1 2 3 4 5 6 ( First round -> 3 is out)
1 2 4 5 6 ( Second round -> 6 is out)
1 2 4 5 ( Third round -> 4 is out)
and so on.
I will store the number that goes out in another vector (resultVect).
Im getting Assertion error. Pls advise tq
When you use erase for a vector, it will relocate the elements after the erase position so the iterators after that will be invalidated.
Second when you say iterator + 2 and that could go beyond the range of the vector too.
Removing an element from the vector invalidates all iterators to that element and beyond (in the current standard, there is an open issue to change this).
The first question is how efficient you want the process to be, if you don't care (much) about performance you can do a simple loop:
for (int i = 3; i < input.size(); i+=3) {
result.push_back(input[i]);
}
for (int i = (input.size()+2)/3 - 1; i >= 0; --i) {
input.erase(input.begin()+i*3);
}
If performance is critical, you can take a look at the std::remove algorithm and use the same approach to avoid doing multiple copies of the elements while you run the algorithm. Basically you need a read and a write head into the original container and you only copy from the read to the write location if the condition is not met.
Simply put: you cannot modify a vector while iterating it. The iterator will become invalid and that will get you an assertion.
To properly do what you want, you might consider creating a copy of the vector with values to keep, and a vector with values to remove. Then replace the number vector by the one with the values to keep.