C++ 从std::vector中删除任意项目列表<;标准::向量<;T>&燃气轮机;

C++ 从std::vector中删除任意项目列表<;标准::向量<;T>&燃气轮机;,c++,c++11,vector,move-semantics,erase-remove-idiom,C++,C++11,Vector,Move Semantics,Erase Remove Idiom,我有一个向量向量,代表一个数组。我希望高效地删除行(以最小的复杂性和分配) 我考虑过构建一个新的向量向量,只复制未删除的行,使用移动语义,如下所示: //std::vector<std::vector<T> > values is the array to remove rows from //std::vector<bool> toBeDeleted contains "marked for deletion" flags for each

我有一个向量向量,代表一个数组。我希望高效地删除行(以最小的复杂性和分配)

我考虑过构建一个新的向量向量,只复制未删除的行,使用移动语义,如下所示:

    //std::vector<std::vector<T> > values is the array to remove rows from
    //std::vector<bool> toBeDeleted contains "marked for deletion" flags for each row

    //Count the new number of remaining rows
    unsigned int newNumRows = 0;
    for(unsigned int i=0;i<numRows();i++)
    {
        if(!toBeDeleted[i])
        {
            newNumRows++;
        }
    }


    //Create a new array already sized in rows
    std::vector<std::vector<T> > newValues(newNumRows);

    //Move rows
    for(unsigned int i=0;i<numRows();i++)
    {
        if(!toBeDeleted[i])
        {
            newValues[i] = std::move(values[i]);
        }
    }

    //Set the new array and clear the old one efficiently
    values = std::move(newValues);
//std::vector values是要从中删除行的数组
//std::vector toBeDeleted包含每行的“标记为删除”标志
//计算新的剩余行数
无符号整数newNumRows=0;

对于(unsigned int i=0;i这可以使用常规的变体来解决,在
std::remove_中有一个lambda,如果
,它在要删除的索引的迭代器范围内查找当前行的索引:

#include <algorithm>    // find, remove_if
#include <iostream>
#include <vector>

template<class T>
using M = std::vector<std::vector<T>>; // matrix

template<class T>
std::ostream& operator<<(std::ostream& os, M<T> const& m)
{
    for (auto const& row : m) {
        for (auto const& elem : row)
            os << elem << " ";
        os << "\n";
    }
    return os;
}

template<class T, class IdxIt>
void erase_rows(M<T>& m, IdxIt first, IdxIt last)
{
    m.erase(
        std::remove_if(
            begin(m), end(m), [&](auto& row) {
            auto const row_idx = &row - &m[0];
            return std::find(first, last, row_idx) != last;
        }), 
        end(m)
    );
}

int main()
{
    auto m = M<int> { { 0, 1, 2, 3 }, { 3, 4, 5, 6 }, { 6, 7, 8, 9 }, { 1, 0, 1, 0 } };
    std::cout << m << "\n";

    auto drop = { 1, 3 };
    erase_rows(m, begin(drop), end(drop));

    std::cout << m << "\n";
}
#包括


注意:因为从C++11开始,
std::vector
具有移动语义,所以在
std::vector
中使用简单的指针操作来移动行,而不考虑类型
T
(不过,如果要删除列,情况会大不相同!).

为什么不直接使用
std::remove\u if
?我严重怀疑您的实现是否更快或使用更少的内存,只需在滚动您自己的实现之前进行概要分析。如果您不进行测量,您只是在猜测。嗯,remove\u if作为参数,它会告诉您是否仅基于项值删除项。我可以没有标记项目本身,我只有一个要删除的索引的bool表。如果您可以在这里执行
std::vec;std::vector remVec;auto begin=std::begin(vec);auto end=std::end(vec);size_t idx=0;std::remove if(begin,end,[&idx,&remVec](const int&){return remVec[idx++]}虽然我不建议设置旗标数组,但是不要设置标志,考虑在最后用最后一个仍然好的元素来交换元素,并保持一个索引,之后所有元素都需要被移除。然后,你要做的就是调用<代码>调整大小< /代码>来进行任何实际的移除。特定顺序您还可以使用
std::vector rows;
跟踪元素的标志(我不知道为什么我一直重复
std::
vector rows;
不会让任何人感到困惑).cute!顺便问一句,你的main中的
drop
类型是什么?@Walter它是
std::initializer\u list
,其中
std::begin()
std::end()
的工作方式与各种标准容器相同。你能解释一下
auto const row\u idx=&row-&m[0];
?@galinette是的,它将行索引计算为第一行和当前行地址之间的差。@TemplateRex:row和m[0]是迭代器,对吗?所以row_idx是迭代器上两个指针之间的差??
#include <algorithm>    // find, remove_if
#include <iostream>
#include <vector>

template<class T>
using M = std::vector<std::vector<T>>; // matrix

template<class T>
std::ostream& operator<<(std::ostream& os, M<T> const& m)
{
    for (auto const& row : m) {
        for (auto const& elem : row)
            os << elem << " ";
        os << "\n";
    }
    return os;
}

template<class T, class IdxIt>
void erase_rows(M<T>& m, IdxIt first, IdxIt last)
{
    m.erase(
        std::remove_if(
            begin(m), end(m), [&](auto& row) {
            auto const row_idx = &row - &m[0];
            return std::find(first, last, row_idx) != last;
        }), 
        end(m)
    );
}

int main()
{
    auto m = M<int> { { 0, 1, 2, 3 }, { 3, 4, 5, 6 }, { 6, 7, 8, 9 }, { 1, 0, 1, 0 } };
    std::cout << m << "\n";

    auto drop = { 1, 3 };
    erase_rows(m, begin(drop), end(drop));

    std::cout << m << "\n";
}