У меня есть 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(vec.begin() + 1);
Или удалить более одного элемента одновременно:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin() + 1, vec.begin() + 3);
operator+
это не обязательно определяется для итераторов на других типах контейнеров, как list<T>::iterator
(вы не можете сделать list.begin() + 2
на условиях std::list
, вы должны использовать std::advance
для этого)
std::find_if
Метод erase в std :: vector перегружен, поэтому его, вероятно, будет понятнее
vec.erase(vec.begin() + index);
когда вы хотите стереть только один элемент.
vec.begin()
что является действительным.
vec.erase(0)
не работает, но vec.erase(vec.begin()+0)
(или без +0) работает. В противном случае я не получаю соответствующий вызов функции, поэтому я пришел сюда
vec.erase(0)
может на самом деле скомпилироваться, если 0
получится интерпретировать как константу нулевого указателя ...
template <typename T>
void remove(std::vector<T>& vec, 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); }
я не говорю, что лучше, просто спрашиваю из личного интереса и возвращаю лучший результат, который мог получить этот вопрос.
vector<T>::iterator
является итератором с произвольным доступом, ваша версия в порядке и, возможно, немного понятнее. Но версия, которую выложил Макс, должна прекрасно работать, если вы измените контейнер на другой, который не поддерживает итераторы с произвольным доступом
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
самом деле вернет вам позицию итератора в этом индексе, что неверно для всех итерируемых контейнеров. Это также постоянная сложность, а не линейная благодаря использованию обратного указателя.
unordered_remove
и unordered_remove_if
… если только это не было, и я пропустил это, что происходит все чаще и чаще в наши дни :)
std::remove
переупорядочивает контейнер так, чтобы все элементы, которые будут удалены, были в конце, нет необходимости делать это вручную, как это, если вы используете C ++ 17.
std::remove
помочь? cppreference утверждает, что даже в C ++ 17 для всех remove
перегрузок требуется предикат, и ни один из них не принимает индекс.
Если вы работаете с большими векторами (размер> 100 000) и хотите удалить много элементов, я бы порекомендовал сделать что-то вроде этого:
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. Это может быть проблемой, если вы перебираете вектор, поскольку vector size () уменьшается. Если у вас есть проблема, подобная этой, предложенная ссылка предложила использовать существующий алгоритм в стандартной библиотеке C ++. и "удалить" или "удалить_if".
Надеюсь что это помогло
Предыдущие ответы предполагают, что у вас всегда есть подписанный индекс. К сожалению, 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));
это удалит ваше значение отсюда. Спасибо
самый быстрый способ (для программирования конкурсов по сложности времени () = константа)
может стереть 100M элемент в 1 секунду;
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
и самый читаемый способ:
vec.erase(vec.begin() + pos);
vector<int>::iterator
не обязательно совпадает сint *