Как удалить элемент из вектора stl с определенным значением? - PullRequest
128 голосов
/ 02 сентября 2008

Я просматривал документацию API для stl vector и заметил, что в классе vector нет метода, который позволял бы удалять элемент с определенным значением. Это похоже на обычную операцию, и странно, что нет встроенного способа сделать это.

Ответы [ 10 ]

151 голосов
/ 02 сентября 2008

std::remove на самом деле не удаляет элемент из контейнера, но он возвращает новый конечный итератор, который может быть передан в container_type::erase для РЕАЛЬНОГО удаления дополнительных элементов, которые теперь находятся в конце контейнера :

std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.erase(std::remove(vec.begin(), vec.end(), int_to_remove), vec.end());
57 голосов
/ 14 апреля 2013

Если вы хотите удалить элемент и , следующее будет более эффективным.

std::vector<int> v;


auto it = std::find(v.begin(), v.end(), 5);
if(it != v.end())
    v.erase(it);

или вы можете избежать накладных расходов на перемещение предметов, если заказ не имеет значения для вас:

std::vector<int> v;

auto it = std::find(v.begin(), v.end(), 5);

if (it != v.end()) {
  using std::swap;

  // swap the one to be removed with the last element
  // and remove the item at the end of the container
  // to prevent moving all items after '5' by one
  swap(*it, v.back());
  v.pop_back();
}
15 голосов
/ 02 сентября 2008

Используйте глобальный метод std :: remove с итератором начала и конца, а затем используйте std :: vector.erase для фактического удаления элементов.

Ссылки на документацию
std :: remove http://www.cppreference.com/cppalgorithm/remove.html
std :: vector.erase http://www.cppreference.com/cppvector/erase.html

std::vector<int> v;
v.push_back(1);
v.push_back(2);

//Vector should contain the elements 1, 2

//Find new end iterator
std::vector<int>::iterator newEnd = std::remove(v.begin(), v.end(), 1);

//Erase the "removed" elements.
v.erase(newEnd, v.end());

//Vector should now only contain 2

Спасибо Джиму Баку за указание на мою ошибку.

5 голосов
/ 02 сентября 2008

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

Если вы интенсивно выполняете эту операцию, по этой причине может оказаться целесообразным рассмотреть std :: set.

5 голосов
/ 02 сентября 2008

Если у вас есть несортированный вектор, то вы можете просто поменять местами последний элемент вектора, тогда resize().

С заказанным контейнером вам лучше всего ‍ std::vector::erase(). Обратите внимание, что std::remove() определено в <algorithm>, но на самом деле стирание не выполняется. (Внимательно прочитайте документацию).

3 голосов
/ 19 июля 2017

Более коротким решением (которое не заставляет вас повторять имя вектора 4 раза) было бы использование Boost:

#include <boost/range/algorithm_ext/erase.hpp>

// ...

boost::remove_erase(vec, int_to_remove);

См. http://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/reference/algorithms/new/remove_erase.html

2 голосов
/ 02 сентября 2008

См. Также std :: remove_if , чтобы использовать предикат ...

Вот пример по ссылке выше:

vector<int> V;
V.push_back(1);
V.push_back(4);
V.push_back(2);
V.push_back(8);
V.push_back(5);
V.push_back(7);

copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
    // The output is "1 4 2 8 5 7"

vector<int>::iterator new_end = 
    remove_if(V.begin(), V.end(), 
              compose1(bind2nd(equal_to<int>(), 0),
                       bind2nd(modulus<int>(), 2)));
V.erase(new_end, V.end()); [1]

copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
    // The output is "1 5 7".
1 голос
/ 15 мая 2019

С с ++ 20 :

Введена функция, не являющаяся членом std::erase, которая принимает вектор и значение для удаления в качестве входных данных.

например:

std::vector<int> v = {90,80,70,60,50};
std::erase(v,50);
0 голосов
/ 03 октября 2018

Существуют два способа, с помощью которых вы можете особенно стереть объект. давайте возьмем вектор

std :: vector < int > v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(40);
v.push_back(50);

1) Неэффективный способ: Хотя это кажется довольно эффективным, но это не потому, что функция стирания удаляет элементы и сдвигает все элементы влево на 1. так что его сложность будет O (n ^ 2)

std :: vector < int > :: iterator itr = v.begin();
int value = 40;
while ( itr != v.end() )
{
   if(*itr == value)
   { 
      v.erase(itr);
   }
   else
       ++itr;
}

2) Эффективный способ (РЕКОМЕНДУЕТСЯ) : Он также известен как УДАЛЕНИЕ - УДАЛИТЬ идиомы .

  • std :: remove преобразует данный диапазон в диапазон со всеми элементами, которые сравниваются не равными данному элементу, смещенными в начало контейнера.
  • Так что на самом деле не удаляйте совмещенные элементы. Он просто сдвинул несоответствие к началу и дает итератору новый действительный конец. Это просто требует сложности O (n).

Вывод алгоритма удаления:

10 20 30 50 40 50 

в качестве возвращаемого типа удаления используется итератор для нового конца этого диапазона.

template <class ForwardIterator, class T>
  ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);

Теперь используйте функцию стирания вектора, чтобы удалить элементы из нового конца в старый конец вектора. Требуется время O (1).

v.erase ( std :: remove (v.begin() , v.end() , element ) , v.end () );

, поэтому этот метод работает в O (n)

0 голосов
/ 02 декабря 2017

Если вы хотите сделать это без каких-либо дополнительных включений:

vector<IComponent*> myComponents; //assume it has items in it already.
void RemoveComponent(IComponent* componentToRemove)
{
    IComponent* juggler;

    if (componentToRemove != NULL)
    {
        for (int currComponentIndex = 0; currComponentIndex < myComponents.size(); currComponentIndex++)
        {
            if (componentToRemove == myComponents[currComponentIndex])
            {
                //Since we don't care about order, swap with the last element, then delete it.
                juggler = myComponents[currComponentIndex];
                myComponents[currComponentIndex] = myComponents[myComponents.size() - 1];
                myComponents[myComponents.size() - 1] = juggler;

                //Remove it from memory and let the vector know too.
                myComponents.pop_back();
                delete juggler;
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...