C++中的std::remove_if

std::remove_if 在 C++ 中是一个算法,用于从序列中移除满足特定条件的元素。它并不实际删除容器中的元素,而是将不被移除的元素移到序列的开始处,并返回一个指向新序列末尾的迭代器。被“移除”元素仍然存在于容器中,但是它们之后的元素都是未指定的值【10†source】。

这个算法接受两个迭代器,表示要处理的元素范围,以及一个一元谓词,当一元谓词对元素求值为真时,该元素就会被移除。例如,如果有一个由整数构成的向量,你想移除所有的负数,你可以定义一个一元谓词,当整数为负时返回真【9†source】。

使用 std::remove_if 时,它将对每个元素应用一元谓词,确切地来说,这个过程会涉及到对序列中每个元素做一次谓词的应用【11†source】。

一个典型的使用 std::remove_if 的例子是,当你有一个字符串,并想移除所有空格。你可以使用 std::remove_if 来逻辑上移除所有空格字符,然后使用字符串的 erase 方法来物理上删除那些元素,这个过程被称为“擦除-移除惯用法”【12†source】【14†source】。

下面是一个具体的实现示例,它展示了如何移除一个字符串中的所有空格【14†source】:

#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
#include <string_view>

int main() {
    std::string str1{"Text with some   spaces"};
    auto noSpaceEnd = std::remove(str1.begin(), str1.end(), ' ');
    std::cout << std::string_view(str1.begin(), noSpaceEnd) << " size: " << str1.size() << '\n';
    str1.erase(noSpaceEnd, str1.end());
    std::cout << str1 << " size: " << str1.size() << '\n';

    std::string str2 = "Text\n with\t some \t  whitespaces\n\n";
    str2.erase(std::remove_if(str2.begin(), 
                              str2.end(),
                              [](unsigned char x) { return std::isspace(x); }),
               str2.end());
    std::cout << str2 << '\n';
}

输出将会是:

Textwithsomespaces size: 23
Textwithsomespaces size: 18
Textwithsomewhitespaces

c.erase(std::remove_if(t.begin(),t.end(),lambda判断函数),e):可实现将t中满足条件的元素全部删掉

  trimmers_.erase(
      std::remove_if(trimmers_.begin(), trimmers_.end(),
                     [](std::unique_ptr<PoseGraphTrimmer>& trimmer) {
                       return trimmer->IsFinished();
                     }),
      trimmers_.end());

remove_if的参数是迭代器,前两个参数表示迭代的起始位置和这个起始位置所对应的停止位置。
最后一个参数:传入一个回调函数,如果回调函数返回为真,则将当前所指向的参数移到尾部。
返回值是 被移动区域的首个元素 【!!!意味着:先将所有满足条件的成员依次挪到尾部,再返回移动区域的首个元素地址】。
remove_if在头文件algorithm中,故要使用此函数,需添加#include
由于remove_if函数的参数是迭代器,通过迭代器无法得到容器本身,
而要删除容器内的元素必须通过容器的成员函数来进行。
因而此函数无法真正删除元素,只能把要删除的元素移到容器末尾并返回要被删除元素的迭代器,
然后通过erase成员函数来真正删除。因为一般remove_if和erase函数是成对出现的。

void nms(std::vector<Detection>& detections, float nms_thresh = 0.4) {
    std::sort(detections.begin(), detections.end(), cmp);

    std::vector<bool> toDelete(detections.size(), false);

    for (size_t i = 0; i < detections.size(); ++i) {
        if (toDelete[i]) continue;  // 如果当前元素已被标记为删除,则跳过

        for (size_t j = i + 1; j < detections.size(); ++j) {
            if (iou(detections[i].bbox, detections[j].bbox) > nms_thresh) {
                toDelete[j] = true;  // 标记为删除
            }
        }
    }

    // 使用擦除-移除惯用法一次性删除所有标记为删除的元素
    auto newEnd = std::remove_if(
        detections.begin(), detections.end(),
        [&toDelete](const Detection& det, size_t idx) { return toDelete[idx]; }
    );

    detections.erase(newEnd, detections.end());  // 实际删除元素
}