I have a std::vector<int>, and I want to delete the n'th element. How do I do that?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
I have a std::vector<int>, and I want to delete the n'th element. How do I do that?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
To delete a single element, you could do:
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
// Deletes the second element (vec[1])
vec.erase(std::next(vec.begin()));
Or, to delete more than one element at once:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(std::next(vec.begin(), 1), std::next(vec.begin(), 3));
Actually, the erase
function works for two profiles:
Removing a single element
iterator erase (iterator position);
Removing a range of elements
iterator erase (iterator first, iterator last);
Since std::vec.begin() marks the start of container and if we want to delete the ith element in our vector, we can use:
vec.erase(vec.begin() + index);
If you look closely, vec.begin() is just a pointer to the starting position of our vector and adding the value of i to it increments the pointer to i position, so instead we can access the pointer to the ith element by:
&vec[i]
So we can write:
vec.erase(&vec[i]); // To delete the ith element
If you have an unordered vector you can take advantage of the fact that it's unordered and use something I saw from Dan Higgins at CPPCON
template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
if ( inIndex < inContainer.size() )
{
if ( inIndex != inContainer.size() - 1 )
inContainer[inIndex] = inContainer.back();
inContainer.pop_back();
return true;
}
return false;
}
Since the list order doesn't matter, just take the last element in the list and copy it over the top of the item you want to remove, then pop and delete the last item.
It may seem obvious to some people, but to elaborate on the above answers:
If you are doing removal of std::vector
elements using erase
in a loop over the whole vector, you should process your vector in reverse order, that is to say using
for (int i = v.size() - 1; i >= 0; i--)
instead of (the classical)
for (int i = 0; i < v.size(); i++)
The reason is that indices are affected by erase
so if you remove the 4-th element, then the former 5-th element is now the new 4-th element, and it won't be processed by your loop if you're doing i++
.
Below is a simple example illustrating this where I want to remove all the odds element of an int vector;
#include <iostream>
#include <vector>
using namespace std;
void printVector(const vector<int> &v)
{
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
}
int main()
{
vector<int> v1, v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i);
}
// print v1
cout << "v1: " << endl;
printVector(v1);
cout << endl;
// print v2
cout << "v2: " << endl;
printVector(v2);
// Erase all odd elements
cout << "--- Erase odd elements ---" << endl;
// loop with decreasing indices
cout << "Process v2 with decreasing indices: " << endl;
for (int i = v2.size() - 1; i >= 0; i--)
{
if (v2[i] % 2 != 0)
{
cout << "# ";
v2.erase(v2.begin() + i);
}
else
{
cout << v2[i] << " ";
}
}
cout << endl;
cout << endl;
// loop with increasing indices
cout << "Process v1 with increasing indices: " << endl;
for (int i = 0; i < v1.size(); i++)
{
if (v1[i] % 2 != 0)
{
cout << "# ";
v1.erase(v1.begin() + i);
}
else
{
cout << v1[i] << " ";
}
}
return 0;
}
Output:
v1:
0 1 2 3 4 5 6 7 8 9
v2:
0 1 2 3 4 5 6 7 8 9
--- Erase odd elements ---
Process v2 with decreasing indices:
# 8 # 6 # 4 # 2 # 0
Process v1 with increasing indices:
0 # # # # #
Note that on the second version with increasing indices, even numbers are not displayed as they are skipped because of i++
If you work with large vectors (size > 100,000) and want to delete lots of elements, I would recommend to do something like this:
int main(int argc, char** argv) {
vector <int> vec;
vector <int> vec2;
for (int i = 0; i < 20000000; i++){
vec.push_back(i);}
for (int i = 0; i < vec.size(); i++)
{
if(vec.at(i) %3 != 0)
vec2.push_back(i);
}
vec = vec2;
cout << vec.size() << endl;
}
The code takes every number in vec that can't be divided by 3 and copies it to vec2. Afterwards it copies vec2 in vec. It is pretty fast. To process 20,000,000 elements this algorithm only takes 0.8 sec!
I did the same thing with the erase-method, and it takes lots and lots of time:
Erase-Version (10k elements) : 0.04 sec
Erase-Version (100k elements) : 0.6 sec
Erase-Version (1000k elements): 56 sec
Erase-Version (10000k elements): ...still calculating (>30 min)
To delete an element use the following way:
// declaring and assigning array1
std:vector<int> array1 {0,2,3,4};
// erasing the value in the array
array1.erase(array1.begin()+n);
For a more broad overview you can visit: http://www.cplusplus.com/reference/vector/vector/erase/
I suggest to read this since I believe that is what are you looking for.https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
If you use for example
vec.erase(vec.begin() + 1, vec.begin() + 3);
you will erase n -th element of vector but when you erase second element, all other elements of vector will be shifted and vector sized will be -1. This can be problem if you loop through vector since vector size() is decreasing. If you have problem like this provided link suggested to use existing algorithm in standard C++ library. and "remove" or "remove_if".
Hope that this helped
The previous answers assume that you always have a signed index. Sadly, std::vector
uses size_type
for indexing, and difference_type
for iterator arithmetic, so they don't work together if you have "-Wconversion" and friends enabled. This is another way to answer the question, while being able to handle both signed and unsigned:
To remove:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
v.erase(iter);
}
To take:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
auto val = *iter;
v.erase(iter);
return val;
}