Я просматривал документацию API для вектора stl и заметил, что в классе вектора не было метода, который позволял бы удалить элемент с определенным значением. Это похоже на обычную операцию, и кажется странным, что для этого нет встроенного способа.
146
Ответы:
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());
источник
vec.end()
гарантированно будет одинаковой с обеих сторон вызоваstd::remove
? Мне кажется, что при чтении других частей сети это безопасно, но об этом следует четко заявить.vec.end()
не обязательно должен быть таким же; это просто должно быть правильным (а это так).vec.end()
должно быть таким же, но это нормально, потому чтоstd::remove
это не меняет. Если бы он его изменил (и аннулировал старое значение), тогда возникла бы проблема: порядок оценки параметров не указан, и поэтому вы не узнаете, действителен ли второйvec.end()
к тому времени, когда он используется. Причина того же проста,std::remove
не меняет размер контейнера, а просто перемещает содержимое.std::remove
только один аргумент; то естьconst char *_Filename
. Какой метод мне нужно вызвать?remove
которая удаляет файл. Вам необходимо включить<algorithm>
, чтобы получить доступ к версии,remove
которая имеет дело с контейнерами.Если вы хотите удалить в элемент, следующий будет немного более эффективным.
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 с итератором начала и конца, а затем используйте 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
Спасибо Джиму Баку за указание на мою ошибку.
источник
В других ответах рассказывается, как это сделать хорошо, но я подумал, что также отмечу, что не очень странно, что этого нет в векторном API: это неэффективный линейный поиск по вектору для значения, за которым следует куча копирования, чтобы удалить его.
Если вы выполняете эту операцию интенсивно, по этой причине может быть лучше рассмотреть std :: set.
источник
Если у вас есть несортированный вектор, тогда вы можете просто поменять местами последний элемент вектора
resize()
.С упорядоченным контейнером, вы будете лучше от с
std::vector::erase()
. Обратите внимание, что существуетstd::remove()
определенный in<algorithm>
, но на самом деле он не стирает. (Внимательно прочтите документацию).источник
Более короткое решение (которое не заставляет вас повторять имя вектора 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
источник
Из c ++ 20 :
Введена функция
std::erase
, не являющаяся членом , которая принимает в качестве входных данных вектор и удаляемое значение.пример:
std::vector<int> v = {90,80,70,60,50}; std::erase(v,50);
источник
map::erase
!См. Также 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".
источник
*
*
C ++ 20 предоставляет простой способ сделать это сейчас. Это очень просто:
#include <vector> ... vector<int> cnt{5, 0, 2, 8, 0, 7}; std::erase(cnt, 0);
Вы должны проверить зЬй :: сотрите и зЬй :: erase_if .
Он не только удалит все элементы значения (здесь '0'), но и сделает это за O (n) временной сложности. Это лучшее, что вы можете получить.
Если ваш компилятор не поддерживает C ++ 20, вам следует использовать идиому удаления-удаления :
#include <algorithm> ... vec.erase(std::remove(vec.begin(), vec.end(), 0), vec.end());
источник
Если вы хотите сделать это без каких-либо дополнительных услуг, включите:
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) Эффективный способ (РЕКОМЕНДУЕТСЯ) : он также известен как УДАЛИТЬ - УДАЛИТЬ идиомы .
вывод алгоритма удаления:
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)
источник