Как удалить элементы из std::vector, заданного списком индексов

У меня есть вектор элементов 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?

Пара идей:

  1. Копировать items в новый вектор по одному элементу за раз, пропуская, если индекс находится в indicesToDelete
  2. Итерация items и для каждого удаления уменьшать все элементы в indicesToDelete, которые имеют больший индекс.
  3. Сначала сортируем indicesToDelete, затем итерируем indicesToDelete, и для каждого удаления увеличиваем indexCorrection, который вычитается из последующих индексов.

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


Edit Вот решение, в основном вариация #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;
}
17
задан tenfour 27 September 2011 в 21:09
поделиться

1 ответ

std::sort() indicesToDelete в порядке убывания, а затем удалить из item в нормальном цикле for. Нет необходимости корректировать индексы.

5
ответ дан 30 November 2019 в 13:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: