Удаление всех элементов из одного вектора, которые содержатся в другом в C ++? - PullRequest
0 голосов
/ 05 декабря 2018

У меня есть 2 вектора vc и v2 Я хочу удалить все элементы из vc, содержащиеся в v2. Я пытаюсь сделать это с помощью 2 вложенных циклов.Однако компилятор выдает ошибку: Debug Assertion Failed.Я хотел бы спросить, почему это и как я могу это исправить?Заранее спасибо!

#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector <string> vc;
vector <string> v2;
int main()
{
    vc.push_back("ala");
    vc.push_back("bala");
    vc.push_back("test");
    vc.push_back("sample");
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    v2.push_back("test");
    v2.push_back("bala");
    for (auto i = vc.begin(); i != vc.end(); i++) {
        for (auto j = v2.begin(); j != v2.end(); j++) {
            if (i == j) {
                vc.erase(i);
            }
        }
    }
    //it should print only ala and sample after  the removal process, but it gives
    //debug assertion error
    for (int i = 0; i < vc.size(); i++) {
        cout << vc[i] << endl;
    }
}

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Если вам разрешено сортировать ввод, вы можете использовать std::set_difference:

std::vector<std::string> vc { "ala", "bala", "test", "sample" };
std::vector<std::string> v2 { "test", "bala" };

std::sort(vc.begin(), vc.end());
std::sort(v2.begin(), v2.end());

std::vector<std::string> res;
std::set_difference(vc.begin(), vc.end(),
                    v2.begin(), v2.end(), 
                    std::back_inserter(res));

Демо

0 голосов
/ 05 декабря 2018

Как отмечено в комментариях, у вас есть неопределенное поведение в вашем фрагменте дважды.Сначала вы сравниваете два итератора, которые не ссылаются на один и тот же контейнер.Во-вторых, итератор vc и переменная цикла i становятся недействительными при вызове vc.erase(i).

Исправление этого является хорошим примером для использования заголовка <algorithm> и распространенных идиом, когда такие вещи реализуются с помощьюРука склонна к ошибкам.То, что вам нужно, это так называемый erase-remove-idiom :

#include <algorithm>

auto isInV2 = [&v2](const auto& element){
    return std::find(v2.cbegin(), v2.cend(), element) != v2.cend(); };

vc.erase(std::remove_if(vc.begin(), vc.end(), isInV2), vc.end());

В зависимости от обстоятельств вашего приложения может также подойти сортировка векторов (или их сортировка)в какой-то момент), а затем используйте бинарный поиск, чтобы проверить наличие элемента, который лучше масштабируется с большими последовательностями.

auto isInV2LogN = [&v2](const auto& element){
    return std::binary_search(v2.cbegin(), v2.cend(), element); };

// Important: v2 must be sorted, otherwise std::binary_search doesn't work:
std::sort(v2.begin(), v2.end());

vc.erase(std::remove_if(vc.begin(), vc.end(), isInV2LogN), vc.end());
...