如何在给定索引列表的情况下从std :: vector中删除项目

ten*_*our 17 c++ algorithm

我有一个项目向量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)
// ???
Run Code Online (Sandbox Code Playgroud)

执行删除的最佳方法是什么,知道每次删除都会影响所有其他索引indicesToDelete

一些想法是:

  1. 一次将items一个项目复制到一个新项目,如果索引在,则跳过indicesToDelete
  2. 迭代items并为每次删除减少所有indicesToDelete具有更大索引的项目.
  3. indicesToDelete先排序,然后迭代indicesToDelete,并为每个删除增量indexCorrection从后续索引中减去.

所有人似乎都在思考这样一个看似微不足道的任务.有更好的想法吗?


编辑这是解决方案,基本上是#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;
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*eas 12

我会去1/3,即:命令索引向量,在数据向量中创建两个迭代器,一个用于读取,一个用于写入.将写入迭代器初始化为要删除的第一个元素,并将读取迭代器初始化为超出该元素的迭代器.然后在循环的每个步骤中将迭代器增加到下一个值(写入),并且不要跳过下一个值(读取)并复制/移动元素.在循环调用结束时erase,丢弃超出最后写入位置的元素.

顺便说一句,这是在STL 的remove/remove_if算法中实现的方法,区别在于您将条件保存在单独的有序向量中.


Con*_*ius 5

std::sort()indicesToDelete按降序排列,然后从删除itemS IN正常for循环。则无需调整索引。

  • 如果操作后的`vector`顺序并不重要,则不要立即删除,而是将索引处的元素与vector的末尾交换,然后在末尾删除最后的`n`个元素,其中`n `是`indicesToDelete`向量中元素的数量。 (3认同)