Как стереть элемент из std :: vector <> по индексу?

У меня есть std :: vector <int>, и я хочу удалить n-й элемент. Как я могу это сделать?

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

vec.erase(???);
17.05.2009 17:59:36
Попробуйте использовать std :: deque, который обеспечивает вставку и удаление на обоих концах.
Dario 17.05.2009 18:20:27
Нет, не стоит использовать deque только потому, что вы можете удалить элемент, это очень плохой совет. Существует множество причин, по которым вы можете использовать deque или vector. Это правда, что удаление элемента из вектора может быть дорогостоящим - особенно если вектор большой, но нет оснований думать, что deque будет лучше, чем вектор из примера кода, который вы только что опубликовали.
Owl 1.04.2017 21:10:27
Например, если у вас есть графическое приложение, в котором вы отображаете «список» вещей, в который вы вставляете / удаляете вещи в интерактивном режиме, подумайте, что вы просматриваете список 50-100 раз каждую секунду, чтобы отобразить их, и вы добавляете / удаляете вещи несколько раз. раз каждую минуту. Поэтому реализация «списка» как вектора, вероятно, является лучшим вариантом с точки зрения общей эффективности.
Michel Billaud 28.05.2017 17:54:22
13 ОТВЕТОВ
РЕШЕНИЕ

Чтобы удалить один элемент, вы можете сделать:

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);
688
6.12.2016 18:34:41
Отметим также , двоичная operator+это не обязательно определяется для итераторов на других типах контейнеров, как list<T>::iterator(вы не можете сделать list.begin() + 2на условиях std::list, вы должны использовать std::advanceдля этого)
bobobobo 14.03.2013 23:35:02
Вы утверждаете, что «+1» - это первый элемент myVector [0] или фактическая позиция myVector [1]
Karl Morrison 19.09.2014 07:38:00
Заранее вы должны сохранить итератор в переменной. Если вы используете std :: next, вы можете сделать это в одной строке: vec.erase (next (begin (vec), 123));
dani 5.10.2016 20:36:33
Спасибо всем, кто ответил. Что мы должны думать о дизайне класса, когда такая простая операция, как удаление элемента, требует, чтобы он пришел в StackOverflow?
Pierre 28.01.2018 18:35:36
@Pierre, потому что числовой индекс определенного элемента не является основной моделью доступа, итератор . Все функции, которые смотрят на элементы контейнера, используют итераторы этого контейнера. Напримерstd::find_if
Caleth 3.07.2018 09:38:05

Метод erase в std :: vector перегружен, поэтому его, вероятно, будет понятнее

vec.erase(vec.begin() + index);

когда вы хотите стереть только один элемент.

210
6.12.2016 18:28:12
Но эта проблема возникает независимо от того, сколько у вас элементов.
Zyx 2000 1.09.2014 09:32:19
если есть только один элемент, индекс равен 0, и вы получите, vec.begin()что является действительным.
Anne Quinn 27.01.2015 18:28:51
Я хотел бы, чтобы кто-то упомянул, что vec.erase(0)не работает, но vec.erase(vec.begin()+0)(или без +0) работает. В противном случае я не получаю соответствующий вызов функции, поэтому я пришел сюда
qrtLs 15.02.2016 20:19:40
@qrtLs vec.erase(0)может на самом деле скомпилироваться, если 0окажется, что интерпретируется как константа нулевого указателя ...
L. F. 24.07.2019 09:51:59
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);
}
56
10.03.2011 20:47:43
Макс, что делает эту функцию лучше, чем: template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }я не говорю, что лучше, просто спрашиваю из личного интереса и возвращаю лучший результат, который мог получить этот вопрос.
user1664047 11.09.2012 20:50:55
@JoeyvG: Поскольку a vector<T>::iteratorявляется итератором с произвольным доступом, ваша версия в порядке и, возможно, немного понятнее. Но версия, которую выложил Макс, должна прекрасно работать, если вы измените контейнер на другой, который не поддерживает итераторы с произвольным доступом
Lily Ballard 11.09.2012 21:28:26
Это лучший ответ, так как он применим и к другим форматам контейнеров. Вы также можете использовать std :: next ().
Bim 23.12.2016 18:27:43

eraseМетод будет использоваться двумя способами:

  1. Стирание одного элемента:

    vector.erase( vector.begin() + 3 ); // Deleting the fourth element
  2. Стирание диапазона элементов:

    vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element
15
27.05.2018 12:34:24
Это дублирующий ответ почти через 7 лет после принятого ответа. Пожалуйста, не делай этого.
AlastairG 26.06.2019 14:55:40

Если вы работаете с большими векторами (размер> 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)
4
6.12.2016 18:39:17
как это отвечает на вопрос?
Regis Portalez 12.05.2016 14:34:39
Интересно, но не актуально для вопроса!
Roddy 9.06.2016 20:30:18
Не будет ли алгоритм на месте быстрее?
user202729 21.09.2016 04:17:52
это std :: remove_if (+
RiaD 5.04.2017 12:19:10

На самом деле, eraseфункция работает для двух профилей:

  • Удаление одного элемента

    iterator erase (iterator position);
  • Удаление ряда элементов

    iterator erase (iterator first, iterator last);

Поскольку std :: vec.begin () отмечает начало контейнера, и если мы хотим удалить i-й элемент в нашем векторе, мы можем использовать:

vec.erase(vec.begin() + index);

Если вы посмотрите внимательно, vec.begin () - это просто указатель на начальную позицию нашего вектора, и добавление значения i к нему увеличивает указатель на позицию i, поэтому вместо этого мы можем получить доступ к указателю на элемент ih:

&vec[i]

Итак, мы можем написать:

vec.erase(&vec[i]); // To delete the ith element
10
6.12.2016 18:41:56
-1 Последняя строка не компилируется (по крайней мере, в VS2017). Код предполагает, что vector :: iterator неявно конструируется из необработанного указателя, что не требуется стандартом.
CuriousGeorge 11.04.2018 16:11:25
Это особенно верно для отладочных итераторов
Nishant Singh 9.05.2019 06:50:42

Чтобы удалить элемент, используйте следующий способ:

// 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/

3
6.06.2018 20:44:56
Рассмотрите возможность использования cppreference . Смотрите это , это и т. Д.
L. F. 7.02.2019 10:13:07

Предыдущие ответы предполагают, что у вас всегда есть подписанный индекс. К сожалению, 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;
}
0
6.12.2016 18:43:39

Если у вас есть неупорядоченный вектор, вы можете воспользоваться тем, что он неупорядочен, и использовать то, что я видел у Дэна Хиггинса в 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;
}

Поскольку порядок списка не имеет значения, просто возьмите последний элемент в списке и скопируйте его поверх элемента, который вы хотите удалить, затем вытолкните и удалите последний элемент.

8
18.09.2017 15:18:54
Я думаю, что это лучший ответ, если вектор неупорядочен. Он не основан на предположении, что на iterator + indexсамом деле вернет вам позицию итератора в этом индексе, что неверно для всех итерируемых контейнеров. Это также постоянная сложность, а не линейная благодаря использованию обратного указателя.
theferrit32 15.03.2018 18:57:02
Это полностью необходимо добавить в стандартную библиотеку как unordered_removeи unordered_remove_if… если только это не было, и я пропустил это, что происходит все чаще и чаще в эти дни :)
Will Crawford 12.03.2020 02:35:35
Если бы предложили использовать перемещение-назначение или своп вместо копирования-назначения.
Carsten S 12.03.2020 10:44:34
std::removeпереупорядочивает контейнер так, чтобы все элементы, которые будут удалены, были в конце, нет необходимости делать это вручную, как это, если вы используете C ++ 17.
keith 20.04.2020 18:45:58

Вот еще один способ сделать это, если вы хотите удалить элемент, найдя его с его значением в векторе, вам просто нужно сделать это на векторе.

vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));

это удалит вашу ценность отсюда. Спасибо

0
23.08.2018 09:03:31

самый быстрый способ (для программирования конкурсов по сложности времени () = константа)

может стереть 100M элемент в 1 секунду;

    vector<int> it = (vector<int>::iterator) &vec[pos];
    vec.erase(it);

и самый читаемый способ: vec.erase(vec.begin() + pos);

-4
26.04.2019 20:04:55
Это очень непереносимо; он будет работать с libstdc ++, но не с libc ++ и не с MSVC. vector<int>::iteratorне обязательно совпадает сint *
Marshall Clow 18.06.2019 05:03:09
Это отвратительно, я думаю, что я изменю libstdc ++, чтобы он не работал.
Jonathan Wakely 18.06.2019 19:23:45

Как насчет этого?

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);
}
0
24.06.2019 06:10:19

Я предлагаю прочитать это, так как я считаю, что это то, что вы ищете. https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom

Если вы используете, например,

 vec.erase(vec.begin() + 1, vec.begin() + 3);

Вы удалите n-й элемент вектора, но при удалении второго элемента все остальные элементы вектора будут смещены, а размер вектора будет равен -1. Это может быть проблемой, если вы перебираете вектор, поскольку vector size () уменьшается. Если у вас есть проблема, подобная этой, предложенная ссылка предложила использовать существующий алгоритм в стандартной библиотеке C ++. и «удалить» или «удалить_if».

Надеюсь что это помогло

3
11.07.2019 07:32:19