У меня есть вектор элементов items
и вектор индексов, который следует удалить из items
:
std::vector<T> items;
std::vector<size_t> indicesToDelete;
items.push_back(a);
items.push_back(b);
items.push_back(c);
items.push_back(d);
items.push_back(e);
indicesToDelete.push_back(3);
indicesToDelete.push_back(0);
indicesToDelete.push_back(1);
// given these 2 data structures, I want to remove items so it contains
// only c and e (deleting indices 3, 0, and 1)
// ???
Какой лучший способ выполнить удаление, зная, что при каждом удалении он влияет на все остальные индексы в indicesToDelete
?
Несколько идей были бы следующими:
- Скопируйте
items
в новый вектор по одному элементу за раз, пропустив, если индекс находится вindicesToDelete
- Iterate
items
и для каждого удаления уменьшите все элементы вindicesToDelete
, которые имеют больший индекс. - Сначала отсортируйте
indicesToDelete
, затем итерайтеindicesToDelete
и для каждого приращения удаления aindexCorrection
, который вычитается из последующих индексов.
Похоже, я слишком задумываюсь о такой, казалось бы, тривиальной задаче. Любые лучшие идеи?
Изменить Вот решение, в основном вариант # 1, но с использованием итераторов для определения блоков для копирования результата.
template<typename T>
inline std::vector<T> erase_indices(const std::vector<T>& data, std::vector<size_t>& indicesToDelete/* can't assume copy elision, don't pass-by-value */)
{
if(indicesToDelete.empty())
return data;
std::vector<T> ret;
ret.reserve(data.size() - indicesToDelete.size());
std::sort(indicesToDelete.begin(), indicesToDelete.end());
// new we can assume there is at least 1 element to delete. copy blocks at a time.
std::vector<T>::const_iterator itBlockBegin = data.begin();
for(std::vector<size_t>::const_iterator it = indicesToDelete.begin(); it != indicesToDelete.end(); ++ it)
{
std::vector<T>::const_iterator itBlockEnd = data.begin() + *it;
if(itBlockBegin != itBlockEnd)
{
std::copy(itBlockBegin, itBlockEnd, std::back_inserter(ret));
}
itBlockBegin = itBlockEnd + 1;
}
// copy last block.
if(itBlockBegin != data.end())
{
std::copy(itBlockBegin, data.end(), std::back_inserter(ret));
}
return ret;
}