У мене є std :: vector <int>, і я хочу видалити n-й елемент. Як це зробити?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
У мене є std :: vector <int>, і я хочу видалити n-й елемент. Як це зробити?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
Відповіді:
Щоб видалити один елемент, ви можете:
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);
operator+
це НЕ обов'язково визначається для ітераторів на інших типах контейнерів, як list<T>::iterator
(ви не можете зробити list.begin() + 2
на умовах std::list
, ви повинні використовувати std::advance
для цього)
std::find_if
Метод стирання на std :: vector перевантажений, тому, ймовірно, зрозуміліше викликати
vec.erase(vec.begin() + index);
коли ви хочете стерти лише один елемент.
vec.begin()
що є дійсним.
vec.erase(0)
це не працює, але vec.erase(vec.begin()+0)
(або без +0). Інакше я не отримую відповідного виклику функції, саме тому я прийшов сюди
vec.erase(0)
може насправді компілюватися, якщо 0
трапляється інтерпретувати як нульову константу вказівника ...
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);
}
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
я не кажу, що і краще, просто просити з особистого інтересу і повернути найкращий результат, який це питання може отримати.
vector<T>::iterator
ітератор із випадковим доступом, ваша версія чудова і, можливо, трохи зрозуміліша. Але версія, яку Макс опублікував, повинна спрацьовувати чудово, якщо ви поміняєте контейнер на інший, який не підтримує ітераторів з випадковим доступом
erase
Метод буде використовуватися двома способами:
Стирання одного елемента:
vector.erase( vector.begin() + 3 ); // Deleting the fourth element
Стирання діапазону елементів:
vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element
Насправді erase
функція працює для двох профілів:
Видалення одного елемента
iterator erase (iterator position);
Видалення діапазону елементів
iterator erase (iterator first, iterator last);
Оскільки std :: vec.begin () позначає початок контейнера, і якщо ми хочемо видалити i-й елемент з нашого вектора, ми можемо використовувати:
vec.erase(vec.begin() + index);
Якщо ви придивитесь уважно, vec.begin () - це лише вказівник на вихідне положення нашого вектора і додає значення i до нього збільшує вказівник на позицію i, тож натомість ми можемо отримати доступ до вказівника до i-го елемента:
&vec[i]
Тож ми можемо написати:
vec.erase(&vec[i]); // To delete the ith element
Якщо у вас є не упорядкований вектор, ви можете скористатися тим, що він не упорядкований, і використовувати щось, що я бачив від Дена Хіггінса в 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;
}
Оскільки порядок списку не має значення, просто візьміть останній елемент у списку і скопіюйте його у верхній частині елемента, який ви хочете видалити, після чого виберіть і видаліть останній елемент.
iterator + index
насправді поверне вам позицію ітератора в цьому індексі, що не стосується всіх ітерабельних контейнерів. Це також постійна складність замість лінійної, скориставшись зворотним вказівником.
unordered_remove
і unordered_remove_if
… якщо це не було, і я його не пропустив, що трапляється все частіше в ці дні :)
std::remove
впорядковує контейнер, щоб усі елементи, які потрібно видалити, були в кінці, не потрібно робити це вручну, як це використовується C ++ 17.
std::remove
допомагає? cppreference стверджує, що навіть у C ++ 17 для всіх remove
перевантажень потрібен предикат, і жоден не приймає індекс.
Якщо ви працюєте з великими векторами (розмір> 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 in vec. Це досить швидко. Для обробки 20 000 000 елементів цей алгоритм займає лише 0,8 сек!
Я робив те ж саме з методом erase, і це займає багато і багато часу:
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)
Для видалення елемента використовуйте наступний спосіб:
// 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/
Я пропоную прочитати це, оскільки я вважаю, що це те, що ви шукаєте. https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
Якщо ви використовуєте, наприклад
vec.erase(vec.begin() + 1, vec.begin() + 3);
ви будете стирати n-й елемент вектора, але коли ви стираєте другий елемент, всі інші елементи вектора будуть зміщені, а розмір вектора - -1. Це може бути проблемою, якщо ви переглядаєте вектор, оскільки розмір вектора () зменшується. Якщо у вас є такі проблеми, як надане посилання, пропонується використовувати існуючий алгоритм у стандартній бібліотеці C ++. і "видалити" або "видалити_іф".
Сподіваюся, що це допомогло
Попередні відповіді передбачають, що у вас завжди є підписаний індекс. На жаль, 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;
}
ось ще один спосіб зробити це, якщо ви хочете видалити елемент, знайшовши це з його значенням у векторному, вам просто потрібно зробити це на векторі.
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
це видалить ваше значення звідси. Дякую
найшвидший спосіб (для програмування конкурсів за часовою складністю () = константа)
можна стерти 100M елемент за 1 секунду;
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
і найбільш читаний спосіб:
vec.erase(vec.begin() + pos);
vector<int>::iterator
не обов’язково те саме, щоint *