I have a std::vector<int>
, and I want to delete the n
th element. How do I do that?
Example:
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?
Example:
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));
operator+
is not necessarily defined for iterators on other container types, like list<T>::iterator
(you cannot do list.begin() + 2
on an std::list
, you have to use std::advance
for that) –
Ullyot begin()
?, why not just 1
? –
Presumable std::find_if
–
Sincere std::vector
into nightmarish std::string
. –
Eskimo at()
and operator[]
) is one of the main distinctive properties of std::vector
. It would only be consistent to also support inserting and erasing at an index. –
Philine The erase
method on std::vector
is overloaded, so it's probably clearer to call
vec.erase(vec.begin() + index);
when you only want to erase a single element.
vec.begin()
which is valid. –
Tersina vec.erase(0)
does not work, but vec.erase(vec.begin()+0)
(or without +0) does. Otherwise I get no matching function call, which is why I came here –
Cosher vec.erase(0)
may actually compile if 0
happens to be interpreted as the null pointer constant ... –
Gallice template <typename T>
void remove(std::vector<T>& vec, std::size_t pos)
{
std::vector<T>::iterator it = vec.begin();
std::advance(it, pos);
vec.erase(it);
}
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
I'm not saying either is better, merely asking out of personal interest and to return the best result this question could get. –
Pillory vector<T>::iterator
is a random-access iterator, your version is fine and maybe a bit clearer. But the version that Max posted should work just fine if you change the container to another one that doesn't support random-access iterators –
Menefee typename std::vector<T>::iterator it = vec.begin();
or just auto it = vec.begin();
–
Sidhu The erase
method will be used in two ways:
Erasing single element:
vector.erase( vector.begin() + 3 ); // Deleting the fourth element
Erasing range of elements:
vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element
Erase an element with index :
vec.erase(vec.begin() + index);
Erase an element with value:
vec.erase(find(vec.begin(),vec.end(),value));
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 the position i
. So, we instead can access the pointer to the i
th element with &vec[i]
:
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.
iterator + index
will actually give you back the iterator position at that index, which is not true of all iterable containers. It is also constant complexity instead of linear by taking advantage of the back pointer. –
Photoactinic unordered_remove
and unordered_remove_if
… unless it has been and I missed it, which is happening more and more often these days :) –
Mange std::remove
reorders the container so that all the elements to be removed are at the end, no need to do it manually like this if you are using C++ 17. –
Pulsate std::remove
help? cppreference claims that even in C++17, all remove
overloads require a predicate, and none take an index. –
Yellowknife 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++
Note also that processing the vector in reverse order, you CAN'T use unsigned types for indices (for (uint8_t i = v.size() -1; ...
won't work). This because when i
equals 0
, i--
will overflow and be equal to 255
for uint8_t
for example (so the loop won't stop as i
will still be >= 0
, and probably out of bounds of the vector).
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)
I suggest you read about the erase–remove idiom.
For example:
vec.erase(vec.begin() + 1, vec.begin() + 3);
With this, you will erase the n
th element of vec
but before you erase the second element, all the other elements of vec
will be shifted and the vector size will be reduced by 1. This can be a problem as you may be looping through vec
while its size()
is decreasing.
If you have problem like this the provided link suggests to use remove
and remove_if
.
std::erase_if
. –
Gelignite 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/
if you need to erase an element inside of a for-loop, do the following:
int i = 0;
while(i < vec.size()){
if(condition)
vec.erase(vec.begin() + i);
else
++i;
}
You need to use the Standard Template Library's std::vector::erase
function.
// Deleting the eleventh element from vector vec
vec.erase( vec.begin() + 10 );
std::vector<T,Allocator>::erase
Usage:
iterator erase (iterator position); // until C++11
iterator erase( const_iterator pos ); // since C++11 and until C++20
constexpr iterator erase( const_iterator pos ); // since C++20
Here there is a single parameter, position
which is an iterator pointing to a single element to be removed from the vector.
Member types iterator
and const_iterator
are random access iterator types that point to elements.
erase
function does the following:
It removes from the vector either a single element (position
) or a range of elements ([first, last)
).
It reduces the container size by the number of elements removed, which are destroyed.
Note: The iterator pos
must be valid and dereferenceable. Thus the end()
iterator (which is valid, but is not dereferenceable) cannot be used as a value for pos
.
The return value is an iterator pointing to the new location of the element that followed the last element that was erased by the function call. This is the container end of the operation that erased the last element in the sequence.
Member type iterator is a random access iterator
type that points to elements.
Here, the time complexity is linear on the number of elements erased (destructions) plus the number of elements after the last element is deleted (moving).
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;
}
here is one more way to do this if you want to delete a element by finding this with its value in vector,you just need to do this on vector.
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
it will remove your value from here. thanks
the fastest way (for programming contests by time complexity() = constant)
can erase 100M item in 1 second;
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
and most readable way :
vec.erase(vec.begin() + pos);
vector<int>::iterator
is not necessarily the same as int *
–
Nasion © 2022 - 2024 — McMap. All rights reserved.