从std::vector中的特定索引中删除

Delete from specific indexes in a std::vector

本文关键字:索引 删除 vector std      更新时间:2023-10-16

假设我有一个包含5个元素的std::向量,我需要从索引1和3中删除元素,这是最快的方法。在标准库中是否有任何辅助方法可以为我做到这一点?

您可以使用erase函数。对于这个特定的案例,你提到了这样的东西:

myvector.erase (myvector.begin()+3);
myvector.erase (myvector.begin()+1);

会成功的。您必须为erase函数提供一个迭代器,我建议您阅读文档以了解其用法。以上内容应该适用于您的情况。请注意,每次擦除调用都会在移除位置后更改其余元素的索引,因为内部数组元素将相对于移除的项目进行调整。

作为对您的评论的回应,您一次只能擦除一个元素,除非它们是连续索引,在这种情况下,您可以使用基于范围的擦除版本,使用开始和结束迭代器。例如,如果您想擦除索引1,2和3,请使用

myvector.erase (myvector.begin()+1,myvector.begin()+4);

正如我已经提到的,在你删除的项目之后,项目的索引将相应地降低。这是不可避免的,因为数组中不能有"间隙"。

这应该是一个使用std::move并且每个元素最多只移动一次的相当有效的实现。它要求对to_remove中要删除的索引进行排序。

template<typename T>
  void remove_index(std::vector<T>& vector, const std::vector<int>& to_remove)
  {
    auto vector_base = vector.begin();
    std::vector<T>::size_type down_by = 0;
    for (auto iter = to_remove.cbegin(); 
              iter < to_remove.cend(); 
              iter++, down_by++)
    {
      std::vector<T>::size_type next = (iter + 1 == to_remove.cend() 
                                        ? vector.size() 
                                        : *(iter + 1));
      std::move(vector_base + *iter + 1, 
                vector_base + next, 
                vector_base + *iter - down_by);
    }
    vector.resize(vector.size() - to_remove.size());
  }
// Usage:
//
// std::vector<std::string> values = { "0", "1", "2", "3", "4", "5"};
// remove_index(values, { 1, 3 });

这比逐个删除它们快得多(尽管在某些情况下仍然可以加快速度):

template<class It>
struct remover
{
    size_t *i;
    It *begin;
    It const *end;
    explicit remover(size_t &i, It &begin, It const &end) : i(&i), begin(&begin), end(&end) { }
    template<class T>
    bool operator()(T const &)
    {
        size_t &i = *this->i;
        It &begin = *this->begin;
        It const &end = *this->end;
        while (begin != end && *begin < i)  /* only necessary in case there are duplicate indices */
        { ++begin;  }
        bool const b = begin != end && *begin == i;
        if (b) { ++begin; }
        ++i;
        return b;
    }
};
template<class Container, class IndexIt>
IndexIt remove_indices(Container &items, IndexIt indices_begin, IndexIt const &indices_end)
{
    size_t i = 0;
    std::sort(indices_begin, indices_end);
    items.erase(std::remove_if(items.begin(), items.end(), remover<IndexIt>(i, indices_begin, indices_end)), items.end());
    return indices_begin;
}
int main()
{
    std::vector<int> items(100);
    std::vector<size_t> indices;
    indices.push_back(5);
    indices.push_back(1);
    remove_indices(items, indices.begin(), indices.end());
}

如果你想擦除矢量中的一些任意元素,你可以用以下方法

for ( int i : { 3, 1 } ) v.erase( std::next( v.begin(), i ) );

请考虑初始值设定项列表中的项应按降序排列。