How do I erase part of a vector? - c++

If my std::vector has 1890 elements, and I want to keep the first 1000 and erase the rest,and then again next 890 elements and erase the first 1000,.. so a loop seems to be necessary.
Is there a more convenient way to do this?

std::vector has an erase member function that allows you to erase a range of elements without using an explicit loop. For example:
std::vector<whatever> x(1890);
// erase first 1000 items
x.erase(x.begin(), x.begin()+1000);

Related

Using remove and then erase to delete elements of container

I am writing this as I am very confused. Am I dreaming or have I always been wrong to what remove does?
Suppose we have a vector of integers:
std::vector<int> v {1, 2, 3, 1, 4, 1}
We want to remove all the number 1 from the vector so:
auto it {std::remove(v.begin(), v.end(), 1)};
Now our container will look like this:
2 3 4 1 1 1 with the iterator it pointing on index 3
After that we use this:
v.erase(it, v.end()); to remove all the elements from the iterator to the end of the vector, corresponding to all the 1s. Isnt this how you remove the elements or am I delusional?
What I was surprised about is that we dont need to add erase. Remove will remove all elements. My professor told me to use erase from the iterator to the end of the vector to delete all the elements after performing remove.
Isnt this how you remove the elements
Yes, remove and erase are used as you described in paragraphs preceding the last one.
Now our container will look like this: 2 3 4 1 1 1
Not quite. The container will look like this: 2 3 4 X X X. Where values X are unspecified. The algorithm doesn't need to bother overwriting the elements in the "removed" partition.
What I was surprised about is that we dont need to add erase.
You don't need to erase if it's fine for the residual elements to remain in the vector. If you do need to erase the elements, you can achieve that by erasing them.
Remove will remove all elements.
As per your earlier description, remove will only move the non-removed elements to the left partition. It will not erase any elements from the container. The size of the container won't change.
P.S. instead of remove-erase idiom, you can use std::erase:
std::erase(v, 1);

how to use erase, partition and iterate together at once on vector of objects

~ i'm learning c++ on my own~
I have a class field vector of objects that I want to iterate through and erase things that don't meet a certain condition.
myVector[0] is {obj1= val 1, obj2= val 2, obj3= val3 }
.
.
.
myVector[i] is {obj1= val x, obj2= val y, obj3= valz }
my issue is in order to pass the value to predicate function i need to access the object id and value at that index. But I don't know how to implement it so that i iterates/ increments.
Or more specifically how to I pass that key value at each index ? I'm asking for syntax help.
something like this:
myVector.erase(std::partition(myVector.begin(),myVector.end(), predicate(myVector[i].obj1)),myVector.end());
obviously there is no way for me to increment i this way.
is there a way to do this without using a for loop
I'm not 100% sure I understand the question, because you seem to be worried about the indexes into the vector. If your predicate needs to look at the indexes and not just the items in the vector, that complicates things.
However, does this solve your problem?
#include <algorithm>
myVector.erase(
std::remove_if(myVector.begin(), myVector.end(), myPredicate),
myVector.end());
This is an example of the so-called "erase / remove idiom." The call to remove_if shifts the elements you want to keep forward in the list the appropriate amount but doesn't truncate the vector. Instead, it returns a pointer to the end of the list, which you can then pass to erase.
(Why can't we do this just a single call, instead of having the confusingly-named erase AND remove together? Because std::remove_if is part of <algorithm>, which consists of generic algorithms that work on anything that supplies the right sort of iterators, whereas erase is special to std::vector. Having a start/end pair of the right sort of iterators gives you enough functionality to do what remove_if does, but doesn't give you the ability to truncate the list directly.)
You can write this using a lambda if you don't want to break the predicate out into its own method. For instance:
myVector.erase(
std::remove_if(myVector.begin(), myVector.end(),
[](const auto & x) { return x.obj1 <= 0; }),
myVector.end());

Insert object at index of vector c++

I need to insert an object to existing vector of objects. I know that i need to use iterator to do it but i dont know how it exactly works.
I have alphabetically sorted vector and i need to insert new object by its name in exact index that i got after some search . So i have this.
vector<Person>people;
int index =54;
Person temp;
people.push_back(temp);//insert at end of vector
people.insert(index, temp);//doesnt work for int
Can anyone help me how to use iterator properly to insert my object to 54th index of vector and move all following object by one index ?
Thank you for any help.
The straight forward answer is you need an iterator. The iterator for std::vector supports random access, which means you can add or subtract an integer value to or from an iterator.
people.insert(people.begin() + index, temp);
The better answer is don't use an index, use an iterator. What is your loop? You should be able to refactor the loop to use an iterator instead of an index.
I have alphabetically sorted vector and i need to insert new object by its name in exact index that i got after some search.
If the vector is sorted alphabetically, then the proper way of inserting an item in the correct position while maintaining the sort order is using the upper_bound function:
people.insert(upper_bound(people.begin(), people.end(), temp), temp);
The function searches the sorted range, and returns the position of the first element that is greater than temp.
Here is a demo on ideone.
Solution:
vector<Person>::iterator iter = people.begin() + index;
people.insert(iter, temp);
Reference:
std::vector::insert()
RandomAccessIterator

Why is erase() function so expensive?

Consider a 2d vector vector < vector <int> > Nand lets say its contents are as follows:
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
So the size of N here is 4 i.e. N.size() = 4
Now, consider the following code :
int i = 0;
while(N != empty()){
N.erase(i);
++i;
}
I calculated the time just for this piece of code alone with various sizes for N and following are the results:
The size of N is 1000
Execution Time: 0.230000s
The size of N is 10000
Execution Time: 22.900000s
The size of N is 20000
Execution Time: 91.760000s
The size of N is 30000
Execution Time: 206.620000s
The size of N is 47895
Execution Time: 526.540000s
My question is why is this function so expensive ? If it is so then conditional erase statements in many programs could take forever just because of this function. It is the same case when I use erase function in std::map too. Is there any alternative for this function. Does other libraries like Boost offer any?
Please do not say I could do N.erase() as a whole because I'm just trying to analyze this function.
Consider what happens when you delete the first element of a vector. The rest of the vector must be "moved" down by one index, which involves copying it. Try erasing from the other end, and see if that makes a difference (I suspect it will...)
Because your algorithm is O(n^2). Each call to erase forces the vector to move all elements after the erased element back. So in your loop with the 4 element vector, the first loop causes 3 elements to be shifted, the second iteration causes 1 element to be shifted, and after that you have undefined behavior.
If you had 8 elements, the first iteration would move 7 elements, the next would move 5 elements, the next would move 3 elements, and the final enumeration would move 1 element. (And again you have undefined behavior)
When you encounter situations like this, generally you should use the standard algorithms (i.e. std::remove, std::remove_if) instead, as they run through the container once and turn typical O(n^2) algorithms into O(n) algorithms. For more information see Scott Meyers' "Effective STL" Item 43: Prefer Algorithm Calls to Explicit Loops.
A std::vector is, internally, just an array of elements. If you delete an element in the middle, all the elements after it have to be shifted down. This can be very expensive - even more so if the elements have a custom operator= that does a lot of work!
If you need erase() to be fast, you should use a std::list - this will use a doubly linked list structure that allows fast erasure from the middle (however, other operations get somewhat slower). If you just need to remove from the start of the list quickly, use std::deque - this creates a linked list of arrays, and offers most of the speed advantages of std::vector while still allowing fast erasures from the beginning or end only.
Furthermore, note that your loop there makes the problem worse - you first scan through all elements equal to zero and erase them. The scan takes O(n) time, the erasure also O(n) time. You then repeat for 1, and so on - overall, O(n^2) time. If you need to erase multiple values, you should take an iterator and go through the std::list yourself, using the iterator variant of erase(). Or if you use a vector, you'll find it can be faster to copy into a new vector.
As for std::map (and std::set) - this isn't a problem at all. std::map is capable of both removing elements at random, as well as searching for elements at random, with O(lg n) time - which is quite reasonable for most uses. Even your naive loop there shouldn't be too bad; manually iterating through and removing everything you want to remove in one pass is somewhat more efficient, but not nearly to the extent that it is with std::list and friends.
vector.erase will advance all elements after i forward by 1. This is an O(n) operation.
Additionally, you're passing vectors by value rather than by reference.
Your code also doesn't erase the entire vector.
For example:
i = 0
erase N[0]
N = {{2, 2, 2, 2}, {3, 3, 3, 3}, {4, 4, 4, 4}}
i = 1
erase N[1]
N = {{2, 2, 2, 2}, {4, 4, 4, 4}}
i = 2
erase N[2] nothing happens because the maximum index is N[1]
Lastly, I don' think that's the correct syntax for vector.erase(). You need to pass in an iterator to the begin location to erase the element you want.
Try this:
vector&ltvector&ltint&gt&gt vectors; // still passing by value so it'll be slow, but at least erases everything
for(int i = 0; i &lt 1000; ++i)
{
vector&ltint&gt temp;
for(int j = 0; j &lt 1000; ++j)
{
temp.push_back(i);
}
vectors.push_back(temp);
}
// erase starting from the beginning
while(!vectors.empty())
{
vectors.erase(vectors.begin());
}
You can also compare this to erasing from the end (it should be significantly faster, especially when using values rather than references):
// just replace the while-loop at the end
while(!vectors.empty())
{
vectors.erase(vectors.end()-1);
}
A vector is an array that grows automatically as you add elements to it. As such, elements in a vector a contiguous in memory. This allows constant time access to an element. Because they grow from the end, they also take amortized constant time to add or remove to/from the end.
Now, what happens when you remove in the middle? Well, it means whatever exists after the erased element must be shifted back one position. This is very expensive.
If you want to do lots of insertion/removal in the middle, use a linked list such as std::list of std::deque.
As Oli said, erasing from the first element of a vector means the elements following it have to be copied down in order for the array to behave as desired.
This is why linked lists are used for situations in which elements will be removed from random locations in the list - it is quicker (on larger lists) because there is no copying, only resetting some node pointers.

Erasing a vector element by key

ive defined the following and filled it with elements:
vector <vector<double> > my_vector;
but i want a delete an element with a specific key...
my_vector.erase(int(specific_key));
but it doesnt allow me. how would i properly dispose of the elements assigned to that key properly?
Assuming by specific_key you mean the element at that position in the vector:
my_vector.erase(my_vector.begin() + specific_key);
Would be the "most correct" answer.
If you meant to delete the element that matches specific_key (which will have to be of type vector<double> in the given example:
my_vector.erase(find(my_vector.begin(), my_vector.end(), specific_key));
erase takes in an iterator as argument.
You can do
my_vector.erase (my_vector.begin() + specific_key);
You can also pass in a range
my_vector.erase (my_vector.begin(), my_vector.begin() + 2);
One thing that you should note is that the size of the vector also gets reduced.
The erase method takes iterators as their argument.
Example
If Specific key is not position and say its some data in vector, then one has to iterate vector for that data and erase particular iterator.