Удаление элементов в векторе

Итак, у меня есть вектор целых чисел без знака (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)).

В структуре у меня есть логическая переменная с именем var. В большинстве случаев var ложно. Я хочу удалить все элементы в vector1, у которых var = true.

Я сделал следующее:

for (unsigned int i = 0; i < vector1.size(); i++)
{
   if (vector2.at(vector1.at(i)).var)
    vector1.erase(vector.begin() + i);
}

Единственная проблема заключается в том, что он не удаляет все истинные элементы. Я запускал цикл for несколько раз, чтобы удалить все значения. Это правильное поведение? Если это не так, где я ошибся?


person OGH    schedule 06.02.2013    source источник
comment
Вы уверены, что не имеете в виду if (vector2.at(vector1.at(i)).var)? int не имеет члена var.   -  person Joseph Mansfield    schedule 06.02.2013
comment
Да, извините, я исправил это в вопросе.   -  person OGH    schedule 06.02.2013


Ответы (3)


Для удаления элементов из вектор.

v.erase(std::remove(v.begin(), v.end(), value), v.begin);

std::remove перемещает элементы в конец вектора, а erase удалит элемент из вектора.

person Tony The Lion    schedule 06.02.2013
comment
Я изучил это, но не знал, как установить значение равным значению var в этом элементе. В качестве обходного пути я просто создал еще один вектор и сохранил соответствующие элементы в новом векторе. - person OGH; 06.02.2013
comment
Технически (и обычно также практически) remove не обязательно перемещает элементы в конец вектора. - person Christian Rau; 06.02.2013

Вы можете сохранить временный вектор, скопировать vector1 и перебрать его в цикле for и удалить из vector1.

person ogzd    schedule 06.02.2013

Вы стираете элементы в векторе, в то же время повторяя его. Таким образом, при стирании элемента вы всегда перепрыгиваете через следующий элемент, так как вы увеличиваете 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

EDIT: И, кстати, как всегда, убедитесь, что вам действительно нужен std::vector::at, а не только [], и имейте в виду последствия обоих (в частности, накладные расходы первого и "возможно, небезопасность " последнего).

person Christian Rau    schedule 06.02.2013