Можно ли расширить идиому "стереть-удалить" для одновременной работы с несколькими контейнерами?

В C++ идиома erase-remove - отличный способ удалить все элементы стандартного контейнера, которые удовлетворяют заданному критерию.

Можно ли расширить идиому удаления-удаления, чтобы работать с несколькими контейнерами одновременно?

То есть можно ли вызвать что-то похожее на erase-remove на одном контейнере, а также удалить соответствующие элементы в другом контейнере?

В моем конкретном случае все контейнеры std::vectors того же размера.

Например, если элементы 0, 3, а также 5 удаляются из первого контейнера, я хотел бы элементы 0, 3, а также 5 также удаляется из второго контейнера.

Можно, например, предварительно вычислить контейнер, помечающий удаляемые элементы, построить предикат для remove_if который просто индексирует в контейнер флага и вызывает erase-remove многократно.

Можно ли делать то, что я хочу, без предварительного вычисления?

1 ответ

Да, ты можешь это сделать. Работает как есть. Я предоставляю пример кода и объясняю его.

// initialises a vector that holds the numbers from 0-9.
  std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  print(v);

  // removes all elements with the value 5
  v.erase( std::remove( v.begin(), v.end(), 5 ), v.end() ); 
  print(v); 

В этом коде мы хотим удалить 5 из вектора v и мы используем std::remove а также std::erase после этого. Вы должны понять, что делает std::remove делать. std::remove Меняет местами элементы в контейнере так, что все удаляемые элементы идут до конца, и эта функция возвращает итератор к первому удаляемому элементу. следующий std::erase берет этот итератор и удаляет все элементы, начиная с этого итератора и до конца контейнера (фактически до второго аргумента. v.end() в нашем случае).

std::vector<int> v1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::vector<int> v2 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 };

auto removeIt=std::remove( v1.begin(), v1.end(), [](const int value){
    return value==0 || value==3 || value==5;
} );

// now v1 = { 1, 2, 4, 6, 7, 8, 9, 0, 3, 5 } and removeIt points to 0 element (next after 9)..
                     // removeIt = ^

std::erase(std::remove_if(v2.begin(),v2.end(),[&](const int value){
    // remove every object that can be found between removeIt and v1.end()
    return std::find(removeIt,v1.end(),value)!=v1.end();
}), v2.end());
// now v2 = { 1, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }
std::erase(removeIt,v1.end());
// now v1 = { 1, 2, 4, 6, 7, 8, 9 }

Этот код делает именно то, что вам нужно.

Другие вопросы по тегам