Я переглянув документацію API для вектору stl і помітив, що в векторному класі не існує методу, який дозволяв би видалити елемент із певним значенням. Це здається звичайною операцією, і здається дивним, що для цього немає побудованого способу.
Я переглянув документацію API для вектору stl і помітив, що в векторному класі не існує методу, який дозволяв би видалити елемент із певним значенням. Це здається звичайною операцією, і здається дивним, що для цього немає побудованого способу.
Відповіді:
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 :: видалити 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()
визначений в <algorithm>
, але це насправді не стирає. (Уважно читайте документацію).
Коротше рішення (яке не змушує вас повторити ім'я вектора 4 рази) - використовувати Boost:
#include <boost/range/algorithm_ext/erase.hpp>
// ...
boost::remove_erase(vec, int_to_remove);
Від 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".
Якщо ви хочете зробити це без зайвих включень:
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)
*
Спільнота C ++ почула ваш запит :)
*
C ++ 20 забезпечує простий спосіб зробити це зараз. Він стає таким же простим, як:
#include <vector>
...
vector<int> cnt{5, 0, 2, 8, 0, 7};
std::erase(cnt, 0);
Слід перевірити std :: erase та std :: erase_if .
Він не тільки видалить усі елементи значення (тут '0'), але і зробить це в O (n) часовій складності. Це найкраще, що можна отримати.
Якщо ваш компілятор не підтримує C ++ 20, вам слід використовувати ідіому стирання-видалення :
#include <algorithm>
...
vec.erase(std::remove(vec.begin(), vec.end(), 0), vec.end());