使用带有lambda谓词的std :: remove_if删除多个元素

时间:2017-04-14 13:40:45

标签: c++ std

使用带有lambda谓词的std :: remove_if同时删除多个元素的最快最有效的方法是什么?目前我有一个具有位置和唯一ID的点结构。在更新循环中,我们填充点向量,并在更新循环结束时添加要删除的点。目前我必须在循环内调用remove_if来从点向量中删除所有已删除的点。例如,如果我们每帧添加10个点,之后我们循环所有点以检查该点是否在屏幕边界之外,如果它是添加到deletedPoints _。

struct Point
{
    /// Position.
    Vector3 position_;
    /// Unique id per point
    int id_;
}

/// Current max id
int maxId_;

/// All points
std::vector<Point> points_;
/// Deleted points
std::vector<Point> deletedPoints_;


//Updates with 60fps
void App::Update()
{
    /// Add 10 points per frame
    for (int i = 0; i < 10; ++i)
    {
        Point newPoint;
        /// Add position
        newPoint.position_ = worldPosition;
        /// Add id starts from 1
        maxId_ += 1;
        startPoint.id_ = maxId_;
        /// Add new point in points
        points_.push(newPoint);
    }

    /// If points outside of screen bounds add them to deletedPoints_
    if (points_.size() > 0)
    {
        for (int i = 0; i < points_.size(); ++i)
        {
            /// Bounds
            Vector2 min = Vector2(0.00,0.00);
            Vector2 max = Vector2(1.00,1.00);
            /// Check Bounds 
            if(points_[i].x < min.x || points_[i].y < min.y || points_[i].x > max.x || points_[i].y > max.y)
            {   
                deletedPoints_.push(points_[i]);
            }

        }

        /// Loop deleted points
        for (int i = 0; i < deletedPoints_.size(); ++i)
        {
            int id = deletedPoints_[i].id_;
            /// Remove by id
            auto removeIt = std::remove_if(points_.begin(), points_.end(),
                                  [id](const TrailPoint2& point)
                                  { return point.id_ == id; });
            points_.erase(removeIt, points_.end());
        }
    }


 }

1 个答案:

答案 0 :(得分:2)

在不改变结构的情况下,最快的解决方法是反转整个循环,然后从lambda中的里面检查 func createSceneContents() { self.backgroundColor = .black self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame) } createSceneContents() ship.physicsBody = SKPhysicsBody(rectangleOf: ship.size) ship.physicsBody?.affectedByGravity = false ship.physicsBody?.isDynamic = true ship.name = "ship" ship.physicsBody?.categoryBitMask = PhysicsCategory.ship ship.physicsBody?.collisionBitMask = PhysicsCategory.ship

然后,让deletedPoints deletedPoints存储您的唯一ID。然后它会相对较快,因为std::set<int>不需要扫描整个容器,尽管最终的复​​杂性仍然不是线性时间。

std::set<int>::find

话虽如此,切换到std::vector<Point> points_; std::set<int> deletedPointIds_; /// Remove by id auto removeIt = std::remove_if(points_.begin(), points_.end(), [&](const TrailPoint2& point) { return deletedPointIds_.count(point.id_); }); points_.erase(removeIt, points_.end()); deletedPointIds_.clear(); 实际更快取决于一些事情;由于std::set元素的存储方式,你会丢失内存局部性并丢弃缓存机会。

另一种方法可能是保持向量(ID不是点!),对其进行预排序,然后使用set来获得快速搜索的好处以及顺序存储数据的好处。但是,执行此搜索可能不适合您的应用程序,具体取决于您拥有的数据量以及执行此算法的频率。

您也可以使用std::binary_search代替std::unordered_set<int>;这与std::set具有相同的问题,但基于散列的查找可能比基于树的查找更快。同样,这完全取决于数据的大小,形式和分布。

最终,唯一可以确定的方法是在模拟范围内尝试一些事情并测量它