Так у меня есть вектор беззнаковых целых (vector<unsigned int>
называется vector1
). У меня есть другой вектор структуры, которую я создал (vector<struct>
называется vector2
). vector<int>
содержит целое число, которое является индексом vector<struct>
, Например, скажем, что vector<int = {5, 17, 18, 19}
, Это означает vector2.at(5) == vector2.at(vector1.at(0))
,
В структуре у меня есть переменная bool под названием var
, В большинстве случаев, var
ложно Я хочу удалить все элементы в vector1
который имеет var
= правда.
То, что я сделал, было:
for (unsigned int i = 0; i < vector1.size(); i++)
{
if (vector2.at(vector1.at(i)).var)
vector1.erase(vector.begin() + i);
}
Единственная проблема в том, что он не удаляет все истинные элементы. Я запустил цикл for несколько раз для удаления всех значений. Это правильное поведение? Если нет, то где я ошибся?
Вы должны использовать стереть-удалить идиому удалить элементы из вектора.
v.erase(std::remove(v.begin(), v.end(), value), v.begin);
std::remove
перемещает элементы в конец вектора и erase
удалит элемент из вектора.
Вы можете сохранить временный вектор, копию vector1
и перебрать его в for
цикл и удалить из vector1
,
Вы стираете элементы в векторе, одновременно перебирая его. Поэтому при стирании элемента вы всегда перепрыгиваете через следующий элемент, так как увеличиваете i
просто укоротив вектор в i
(было бы еще хуже, если бы вы использовали правильный цикл итератора вместо цикла индекса). Лучший способ сделать это — разделить обе функции, сначала «Маркировка» (или, вернее, переупорядочение) элементов для удаления и последующего удаления их из вектора.
На практике это лучше всего сделать, используя стереть-удалить идиому (vector.erarse(std::remove(...), vector.end())
), который первым использует std::remove(_if)
реорганизовать данные с не удаленными элементами в начале и вернуть новый конец диапазона, который затем можно использовать для реального удаления этих удаленных элементов из диапазона (эффективно просто сокращая весь вектор), используя std::vector::erase
. Используя лямбду C ++ 11, условие удаления может быть выражено довольно легко:
vector1.erase(std::remove_if( //erase range starting here
vector1.begin(), vector1.end(), //iterate over whole vector
[&vector2](unsigned int i) //call this for each element
{ return vector2.at(i).var; }), //return true to remove
vector1.end()); //erase up to old end
РЕДАКТИРОВАТЬ: И, кстати, как всегда будьте уверены, если вам действительно нужно std::vector::at
вместо просто []
и имейте в виду последствия обоих (в частности, накладные расходы первого и «может быть незащищенность» из последних).