У меня есть std :: vector ‹int>, и я хочу удалить n-й элемент. Как я могу это сделать?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
У меня есть std :: vector ‹int>, и я хочу удалить n-й элемент. Как я могу это сделать?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
Чтобы удалить один элемент, вы можете:
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()));
Или, чтобы удалить сразу несколько элементов:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(std::next(vec.begin(), 1), std::next(vec.begin(), 3));
operator+
не обязательно определен для итераторов в других типах контейнеров, например list<T>::iterator
(вы не можете использовать list.begin() + 2
для std::list
, вы должны использовать _ 5_ для этого)
- person bobobobo; 15.03.2013
begin()
? Почему не просто 1
?
- person user25; 10.04.2018
std::find_if
- person Caleth; 03.07.2018
std::vector
в кошмарное std::string
.
- person Evg; 17.07.2021
Метод стирания в std :: vector перегружен, поэтому, вероятно, проще вызвать
vec.erase(vec.begin() + index);
когда вы хотите стереть только один элемент.
vec.begin()
, что является допустимым.
- person Anne Quinn; 27.01.2015
vec.erase(0)
не работает, а vec.erase(vec.begin()+0)
(или без +0) работает. В противном случае я не получу соответствующего вызова функции, поэтому я пришел сюда
- person qrtLs; 15.02.2016
vec.erase(0)
может фактически компилироваться, если 0
интерпретируется как константа нулевого указателя ...
- person L. F.; 24.07.2019
Метод erase
будет использоваться двумя способами:
Удаление отдельного элемента:
vector.erase( vector.begin() + 3 ); // Deleting the fourth element
Стирание ряда элементов:
vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element
Фактически функция erase
работает для двух профилей:
Удаление одного элемента
iterator erase (iterator position);
Удаление ряда элементов
iterator erase (iterator first, iterator last);
Поскольку std :: vec.begin () отмечает начало контейнера, и если мы хотим удалить i-й элемент в нашем векторе, мы можем использовать:
vec.erase(vec.begin() + index);
Если вы присмотритесь, vec.begin () - это просто указатель на начальную позицию нашего вектора, и добавление к нему значения i увеличивает указатель на позицию i, поэтому вместо этого мы можем получить доступ к указателю на i-й элемент следующим образом:
&vec[i]
Итак, мы можем написать:
vec.erase(&vec[i]); // To delete the ith element
Если у вас неупорядоченный вектор, вы можете воспользоваться тем фактом, что он неупорядочен, и использовать то, что я видел у Дэна Хиггинса из 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;
}
Поскольку порядок в списке не имеет значения, просто возьмите последний элемент в списке и скопируйте его поверх элемента, который вы хотите удалить, затем вытолкните и удалите последний элемент.
iterator + index
фактически вернет вам позицию итератора по этому индексу, что не верно для всех повторяемых контейнеров. Это также постоянная сложность вместо линейной за счет использования обратного указателя.
- person theferrit32; 15.03.2018
unordered_remove
и unordered_remove_if
... если только это не было, и я пропустил это, что в наши дни происходит все чаще и чаще :)
- person Will Crawford; 12.03.2020
std::remove
переупорядочивает контейнер так, чтобы все удаляемые элементы находились в конце, нет необходимости делать это вручную, если вы используете C ++ 17.
- person keith; 20.04.2020
std::remove
помогает? cppreference утверждает, что даже в C ++ 17 все remove
перегрузки требуют предиката, и ни одна из них не принимает индекс.
- person Paul Du Bois; 27.05.2020
Некоторым это может показаться очевидным, но уточним приведенные выше ответы:
Если вы удаляете std::vector
элементы, используя erase
в цикле по всему вектору, вы должны обрабатывать свой вектор в обратном порядке, то есть используя
for (int i = v.size() - 1; i >= 0; i--)
вместо (классический)
for (int i = 0; i < v.size(); i++)
Причина в том, что на индексы влияет erase
, поэтому, если вы удалите 4-й элемент, бывший 5-й элемент теперь станет новым 4-м элементом, и он не будет обрабатываться вашим циклом, если вы выполняете i++
.
Ниже приведен простой пример, иллюстрирующий это, где я хочу удалить все элементы odds вектора int;
#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;
}
Выход:
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 # # # # #
Обратите внимание, что во второй версии с увеличивающимися индексами четные числа не отображаются, так как они пропускаются из-за i++
Сотрите элемент с индексом:
vec.erase(vec.begin() + index);
Удалите элемент со значением:
vec.erase(find(vec.begin(),vec.end(),value));
Если вы работаете с большими векторами (размер> 100000) и хотите удалить много элементов, я бы рекомендовал сделать что-то вроде этого:
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;
}
Код берет каждое число в vec, которое нельзя разделить на 3, и копирует его в vec2. После этого он копирует vec2 в vec. Это довольно быстро. Для обработки 20 000 000 элементов этот алгоритм занимает всего 0,8 секунды!
Я проделал то же самое с методом стирания, и на это уходит много-много времени:
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)
Чтобы удалить элемент, используйте следующий способ:
// declaring and assigning array1
std:vector<int> array1 {0,2,3,4};
// erasing the value in the array
array1.erase(array1.begin()+n);
Чтобы получить более широкий обзор, посетите: http://www.cplusplus.com/reference/vector/vector/erase/
Предлагаю прочитать это, поскольку считаю, что это именно то, что вы ищете. https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
Если вы используете, например,
vec.erase(vec.begin() + 1, vec.begin() + 3);
вы удалите n-й элемент вектора, но когда вы удалите второй элемент, все остальные элементы вектора будут сдвинуты, а размер вектора будет равен -1. Это может быть проблемой, если вы перебираете вектор, поскольку размер вектора () уменьшается. Если у вас есть проблема, как эта, предоставленная ссылка предлагает использовать существующий алгоритм в стандартной библиотеке C ++. и «удалить» или «удалить_если».
Надеюсь, что это помогло
Предыдущие ответы предполагают, что у вас всегда есть индекс со знаком. К сожалению, std::vector
использует size_type
для индексации и difference_type
для арифметики итератора, поэтому они не работают вместе, если у вас включен "-Wconversion" и друзья. Это еще один способ ответить на вопрос, имея возможность обрабатывать как подписанные, так и неподписанные:
Удалять:
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);
}
Принять:
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;
}
вот еще один способ сделать это, если вы хотите удалить элемент, найдя его по его значению в векторе, вам просто нужно сделать это в векторе.
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
он удалит ваше значение отсюда. Благодарность
Как насчет этого?
void squeeze(vector<int> &v)
{
int j = 0;
for (int i = 1; i < v.size(); i++)
if (v[i] != v[j] && ++j != i)
v[j] = v[i];
v.resize(j + 1);
}
если вам нужно стереть элемент внутри цикла for, сделайте следующее:
for(int i = 0; i < vec.size(); i++){
if(condition)
vec.erase(vec.begin() + i);
}
самый быстрый способ (для олимпиад по программированию по временной сложности () = константа)
может стереть 100M элементов за 1 секунду;
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
и наиболее читаемый способ: vec.erase(vec.begin() + pos);
vector<int>::iterator
не обязательно то же самое, что int *
- person Marshall Clow; 18.06.2019
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
Я не говорю, что то и другое лучше, просто спрашиваю из личного интереса и для того, чтобы получить лучший результат, который может получить этот вопрос.
- person ; 12.09.2012
vector<T>::iterator
является итератором с произвольным доступом, ваша версия в порядке и, возможно, немного понятнее. Но версия, которую опубликовал Макс, должна работать нормально, если вы измените контейнер на другой, который не поддерживает итераторы с произвольным доступом.
- person Lily Ballard; 12.09.2012