Как удалить элемент из вектора stl с определенным значением?
Я смотрел документацию API для STL vector и заметил, что в классе vector не было метода, который позволял бы удалять элемент с определенным значением. Это похоже на обычную операцию, и кажется странным, что нет встроенного способа сделать это.
9 ответов:
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());
Если вы хотите удалить an пункт, следующее будет немного более эффективным.
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(); }
используйте глобальный метод std::remove с итератором begin и end, а затем используйте std:: vector.стереть, чтобы на самом деле удалить элементы.
ссылки на документацию
std:: remove http://www.cppreference.com/cppalgorithm/remove.html
СТД::вектор.стереть http://www.cppreference.com/cppvector/erase.htmlstd::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спасибо Джим бак за указание на мою ошибку.
другие ответы охватывают, как это сделать хорошо, но я думал, что также отмечу, что это не очень странно, что это не в векторном API: это неэффективный линейный поиск по вектору для значения, за которым следует куча копирования, чтобы удалить его.
Если вы делаете эту операцию интенсивно, это может быть стоит рассмотреть std::set вместо этого по этой причине.
если у вас есть несортированный вектор, то вы можете просто поменять последний элемент вектора, то
resize().с заказанным контейнером вам будет лучше всего с
std::vector::erase(). Обратите внимание, что естьstd::remove()определена в<algorithm>, но это на самом деле не делает стирание. (Внимательно прочитайте документацию).
см. также 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".
более короткое решение (которое не заставляет вас повторять имя вектора 4 раза) будет использовать Boost:
#include <boost/range/algorithm_ext/erase.hpp> // ... boost::remove_erase(vec, int_to_remove);
Если вы хотите сделать это без лишних включает в себя:
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; } } } }
двумя способами, с помощью которых вы можете использовать, чтобы стереть элемент в частности. давайте возьмем вектор
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)
Comments