【问题标题】:C++ std::find_if on iterator in reverse order迭代器上的 C++ std::find_if 以相反的顺序
【发布时间】:2023-01-14 06:04:57
【问题描述】:

在下面的代码中,是否有一种优雅的方式来找到it_end

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <type_traits>

template <class Iterator, class U = typename std::iterator_traits<Iterator>::value_type>
void process(Iterator begin, Iterator end)
{
    // first nonzero
    auto it_begin = std::find_if(begin, end, [](U val){return val != 0;});

    // end of nonzero values
    int n = std::distance(begin, end);
    int index = n-1;
    for(int i=n-1; i>=0; --i) {
        if(*(begin+i) == 0) {
            index = i;
        } else {
            break;
        }
    }
    auto it_end = begin;
    std::advance(it_end, index);
    // ******* is there a way to use std::find_if or similar function to get it_end? *******

    for(auto it=it_begin; it!=it_end; ++it) {
        // a whole bunch of things
        // ...
        std::cout << *it << std::endl;
    }
}


int main()
{
    std::vector<int> v{0,0,1,2,3,0,0};

    process(v.begin(), v.end());
}

【问题讨论】:

  • @alamin39 那么在第一个 for 循环中, *(begin+i) 的使用不正确吗?
  • @alamin39 这是错误的:cplusplus.com/reference/iterator
  • 是啊谢谢。如果迭代器是随机访问迭代器,它就可以工作,向量的迭代器是。它不适用于 map, set。我只是搞砸了。
  • std::find_if(rbegin, rend, [](U val){return val != 0;}); -> 你可以试试这个。它可能会起作用。顺便说一句,标头后的using namespace std; 将帮助您删除每一行中的std::。看起来更干净。

标签: c++ algorithm


【解决方案1】:

使用std::reverse_iterator

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <type_traits>
#include <list>

template <class Iterator, class U = typename std::iterator_traits<Iterator>::value_type>
void process(Iterator begin, Iterator end)
{
    // first nonzero
    auto it_begin = std::find_if(begin, end, [](U val){return val != 0;});
    if (it_begin == end) 
        return; // all value is zeros. 

    // reverser iterator
    auto r_begin = std::reverse_iterator(end);
    auto r_end = std::reverse_iterator(it_begin);
    auto r_find = std::find_if(r_begin, r_end, [](U val) { return val != 0; });
    auto it_end = r_find.base();

    
    for(auto it = it_begin; it != it_end; ++it) {
        std::cout << *it << std::endl;
    }
}


int main()
{
    std::list<int> v{0,0,0,2,0,3,4};
    process(v.begin(), v.end());
}

【讨论】:

  • 这很好用。另外,all value is zeros 部分对我有帮助。
【解决方案2】:

您可以使用reverse iterator

我的实施:

template <class Iterator, class U = typename std::iterator_traits<Iterator>::value_type>
void yet_another_process(Iterator begin, Iterator end, std::reverse_iterator<Iterator> rbegin, std::reverse_iterator<Iterator> rend) {
    auto it_begin = std::find_if(begin, end, [](U val) { return val != 0; });
    auto it_end = std::find_if(rbegin, rend, [](U val) { return val != 0; }).base();    // Notice this base()
    for (auto it = it_begin; it != it_end; ++it) {
        std::cout << *it << std::endl;
    }
}

main()

int main() {
    std::vector<int> v { 0, 0, 1, 2, 3, 0, 0 };
    yet_another_process(v.begin(), v.end(), v.rbegin(), v.rend());
}

反向迭代器的 base() 方法返回底层的“普通”迭代器。

【讨论】:

  • 感谢传递反向迭代器的想法。
猜你喜欢
  • 2012-01-09
  • 1970-01-01
  • 2019-01-15
  • 2015-03-26
  • 2011-01-30
  • 2015-12-09
  • 1970-01-01
  • 2020-11-23
  • 2012-05-22
相关资源
最近更新 更多