c++ 根据下一个元素的值从vector中删除元素

6ju8rftf  于 2023-05-30  发布在  其他
关注(0)|答案(1)|浏览(115)

我正在写一个程序,它将读取一个字符串向量,如果它遇到一个值为“..”的元素,它将删除自己和前一个元素。(例如{“1”,“2”,“..",“3”}将转换为{“1”,“3”})
我知道我可以使用循环和erase()等编写代码来实现这一点,但我想知道是否可以使用标准库容器函数(如remove_if()for_each()等)来实现这一点,因为这会使我的代码看起来更干净。
我已经看过了,但没有在标准库中找到任何删除/擦除这种风格的元素的东西。

ni65a41a

ni65a41a1#

**TLDR:**可以使用向量函数完成,但由于性能和可读性的原因,不建议在您的情况下使用。下面是你要求的代码,以及我推荐的代码。

我们先来说说你提到的功能:

  • remove_if():此函数删除所有满足 predicate 的元素,并返回新向量范围的迭代器。它不返回被移除元素的单个迭代器,因此不允许移除依赖于它们的元素。
  • for_each():此函数允许您为vector中包含的每个元素运行一个函数。然而,如这里所示,函数将目标指向向量的每个元素的直接值,而不是迭代器。因此,不能擦除依赖于正在迭代的元素的元素。另外,在使用此函数迭代向量时,可能会导致从向量中删除元素的问题。

我能找到的最适合您使用的函数是find_if()。它可以让你找到第一个满足向量中 predicate 的迭代器,如果没有找到,就返回向量的结束迭代器。
这个函数利用了它:

#include <string>
#include <vector>
#include <algorithm>

void processvec(std::vector<std::string>& vec) {
    std::vector<std::string>::iterator found;
    while ((found = std::find_if(vec.begin(), vec.end(), [](std::string str) {return str == ".."; })) != vec.end()) {
        vec.erase(vec.erase(found - 1));
    }
}

简单解释一下:

  • 我们声明一个“发现”迭代器
  • 然后,我们进入一个while循环,它将在每次迭代中找到第一个迭代器,该迭代器对应于向量中等于“...”的元素。
  • 如果找到的迭代器等于向量的结束迭代器,我们就中断while循环
  • 如果while循环没有中断,那么我们从向量中删除找到的迭代器之前的元素
  • erase函数返回向量的下一个有效操作符
  • 因此,我们也删除了新返回的迭代器。
  • 重复while循环

但要注意两件事:

  • 输入向量必须有效:例如,如果你输入{"..", "1", "2"},就会发生错误,因为在第一个“..”之前没有元素。
  • 虽然这回答了你“使用标准库容器函数”的要求,但它的效率非常低,因为find_if()函数每次被调用时都会遍历你的向量。因此,在一个有一千个元素的大规模向量上,只有最后几个元素实际上是“..”,那么数百个元素将被迭代多次而一无所获。

因此,我认为在您的情况下,坚持使用通常的循环迭代器将是一个更好的主意。
下面是一个应该足够有效地完成这项工作的函数:

#include <string>
#include <vector>
#include <algorithm>
    
void processvec(std::vector<std::string>& vec) {
    for (std::vector<std::string>::iterator it = vec.begin(); it != vec.end();) {
        if (*it == ".." && it != vec.begin())
            it = vec.erase(vec.erase(it - 1));
        else
            ++it;
    }
}

我不确定这里的客观可读性如何,但我发现前一个函数比后一个函数更难阅读,因为前一个函数上堆积了太多东西。

相关问题