C++ 如何根据另一个向量中的条件从向量中删除元素?

C++ 如何根据另一个向量中的条件从向量中删除元素?,c++,stl,C++,Stl,我有两个等长的向量,我想根据其中一个向量中的条件从中删除元素。应将相同的删除操作应用于两者,以便索引匹配 我提出了一个使用std::erase的解决方案,但速度非常慢: vector<myClass> a = ...; vector<otherClass> b = ...; assert(a.size() == b.size()); for(size_t i=0; i<a.size(); i++) { if( !a[i].alive() ) {

我有两个等长的向量,我想根据其中一个向量中的条件从中删除元素。应将相同的删除操作应用于两者,以便索引匹配

我提出了一个使用
std::erase
的解决方案,但速度非常慢:

vector<myClass> a = ...;
vector<otherClass> b = ...;
assert(a.size() == b.size());
for(size_t i=0; i<a.size(); i++)
{
    if( !a[i].alive() )
    {

        a.erase(a.begin() + i);
        b.erase(b.begin() + i);
        i--;
    }
}
向量a=。。。; 向量b=。。。; 断言(a.size()==b.size());
对于(size_t i=0;i来说,它之所以慢,可能是因为O(n^2)的复杂性。为什么不使用列表呢?因为制作一对a和b也是一个好主意。

一个快速的成功方法是向后运行循环:即从向量的末尾开始。这有助于减少由于元素移除而导致的向后移位次数


另一种方法是考虑<代码> STD::vector < /代码>等:那么,你将基本上是移动指针而不是值。

< P>如果命令不重要,你可以<代码>交换< /COD>元素到向量的后面并弹出它们。

for(size_t i=0; i<a.size();)
{
    if( !a[i].alive() )
    {
        std::swap(a[i], a.back());
        a.pop_back();
        std::swap(b[i], b.back());
        b.pop_back();
    }
    else
      ++i;
}

我建议您创建2个新向量,最后保留内存并交换向量内容

vector<myClass> a = ...;
vector<otherClass> b = ...;
vector<myClass> new_a; 
vector<myClass> new_b;
new_a.reserve(a.size());
new_b.reserve(b.size());
assert(a.size() == b.size());
for(size_t i=0; i<a.size(); i++)
{
    if( a[i].alive() )
    {
        new_a.push_back(a[i]);
        new_b.push_back(b[i]);
    }
}
swap(a, new_a);
swap(b, new_b);
向量a=。。。; 向量b=。。。; 矢量新_a; 向量新_b; 新储备(a.尺寸()); 新储备(b.大小()); 断言(a.size()==b.size());
对于(sisixt i=0;i<p>从向量中间擦除是缓慢的,因为它需要在删除点之后重新调整所有的内容。考虑使用另一个容器,而不是更快地擦除。这取决于您的用例,是否经常迭代?数据是否需要排序?如果不经常迭代,请考虑一个列表。为了维护顺序,考虑一个集合。如果你经常迭代并且需要维护顺序,取决于元素的数量,将所有活着的元素推回到一个新的向量,并将A/B设置为指向那个,可能会更快。
此外,由于数据本质上是链接的,因此在一对或小结构中只有一个向量包含数据a和b似乎是有意义的。

出于性能原因,需要使用next。 使用

向量
比如说@Basheba和std::sort。
使用特殊形式的std::sort和比较谓词。不要从0到n枚举。使用std::lower_bound,因为向量将被排序。元素的插入类似于此问题中的say CashCow:“

我有两个类似的问题:

std::<Eigen::Vector3d> points;
std::<Eigen::Vector3d> colors;
std::points;
标准:颜色;
对于Open3D中的3D点云,在移除地板后,如果点的z坐标大于0.05,我想删除所有点和颜色。我最终基于索引覆盖点,并随后调整向量大小

bool invert = true;
std::vector<bool> mask = std::vector<bool>(points.size(), invert);
size_t pos = 0;
for (auto & point : points) {
    if (point(2) < CONSTANTS::FLOOR_HEIGHT) {
        mask.at(pos) = false;
    }
    ++pos;
}
size_t counter = 0;
for (size_t i = 0; i < points.size(); i++) {
    if (mask[i]) {
        points.at(counter) = points.at(i);
        colors.at(counter) = colors.at(i);
        ++counter;
    }
}
points.resize(counter);
colors.resize(counter);
bool invert=true;
std::vector mask=std::vector(points.size(),反转);
大小\u t pos=0;
用于(自动点:点(&P){
if(点(2)<常数::楼层高度){
掩码.at(pos)=假;
}
++pos;
}
计数器的大小=0;
对于(size_t i=0;i
这保持了秩序,至少在我的案例中,其工作速度几乎是公认答案中remove_if方法的两倍: 对于921600点,运行时为:

  • 接受的答案为33毫秒
  • 17毫秒,用于此方法

出于兴趣,为什么不能使用
向量a_和_b
?这并不是那么容易。搜索“zip迭代器”可以找到这样的问题,只需将
std::sort
替换为
向量。擦除(std::remove)
,也许可以。这很可爱,因为它利用了引擎盖下的移动语义,再加上一个。(尽管可能会在回答中解释这一点)非常感谢。我从来没有遇到过列表中C++有用的情况。这不是最佳的解决方案,只是认为它是性能和可读性之间的一个很好的折衷。当你在列表中获得元素时,你也会得到缓存缺失,如果你对性能感兴趣,我认为这是一个很糟糕的权衡。取决于数据结构法的大小。如果数据结构足够大,则无论如何都会强制获取缓存未命中。
std::<Eigen::Vector3d> points;
std::<Eigen::Vector3d> colors;
bool invert = true;
std::vector<bool> mask = std::vector<bool>(points.size(), invert);
size_t pos = 0;
for (auto & point : points) {
    if (point(2) < CONSTANTS::FLOOR_HEIGHT) {
        mask.at(pos) = false;
    }
    ++pos;
}
size_t counter = 0;
for (size_t i = 0; i < points.size(); i++) {
    if (mask[i]) {
        points.at(counter) = points.at(i);
        colors.at(counter) = colors.at(i);
        ++counter;
    }
}
points.resize(counter);
colors.resize(counter);