找到满足条件的第n个元素?

时间:2013-07-25 18:03:14

标签: c++ c++11 find stl-algorithm

是否有几个std::algorithm/lambda function访问满足给定条件的nth元素。由于std::find_if会访问第一个,因此找到nth一个是等价的吗?

3 个答案:

答案 0 :(得分:13)

您需要创建一个有状态谓词,该谓词将计算实例数,然后在达到预期计数时完成。现在的问题是,在算法评估过程中,不能保证复制谓词的次数,因此你需要在谓词本身之外保持这种状态,这使得它有点难看,但是你可以做:

iterator which;
{  // block to limit the scope of the otherwise unneeded count variable
   int count = 0;
   which = std::find_if(c.begin(), c.end(), [&count](T const & x) {
        return (condition(x) && ++count == 6)
   });
};

如果经常出现这种情况,并且您不关心性能,则可以编写一个谓词适配器,在内部创建一个shared_ptr并更新它。同一个适配器的多个副本将共享相同的实际计数对象。

另一种选择是实现find_nth_if,这可能更简单。

#include <iterator>
#include <algorithm>

template<typename Iterator, typename Pred, typename Counter>
Iterator find_if_nth( Iterator first, Iterator last, Pred closure, Counter n ) {
  typedef typename std::iterator_traits<Iterator>::reference Tref;
  return std::find_if(first, last, [&](Tref x) {
    return closure(x) && !(--n);
  });
}

http://ideone.com/EZLLdL

答案 1 :(得分:3)

大卫的答案很好。我只需要指出谓词可以通过使用Boost.Iterator库,特别是boost::filter_iterator适配器抽象到迭代器中,它的优势在于它可以用于更多的算法。 (例如):

#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/iterator/filter_iterator.hpp>

template<class ForwardIt, class Predicate, class Size>
ForwardIt find_if_nth(ForwardIt first, ForwardIt last, Predicate pred, Size n)
{
    auto vb = boost::make_filter_iterator(pred, first, last);
    auto const ve = boost::make_filter_iterator(pred, last, last);
    while (vb != ve && --n)
        ++vb;
    return vb.base();
}

int main()
{
    auto const v = std::vector<int>{ 0, 0, 3, 0, 2, 4, 5, 0, 7 };
    auto const n = 2;
    auto const pred = [](int i){ return i > 0; };
    auto const nth_match = find_if_nth(v.begin(), v.end(), pred, n);

    if (nth_match != v.end())
        std::cout << *nth_match << '\n';
    else
        std::cout << "less than n elements in v matched predicate\n";
}

Live example。这将打印2(第二个元素&gt; 0,从1开始计数,以便find_iffind_if_nth匹配n==1。如果谓词更改为i > 10或者第n个元素更改为n = 6,它将返回结束迭代器。

答案 2 :(得分:3)

类似STL的函数模板将是:

template<class InputIterator, class NthOccurence class UnaryPredicate>
InputIterator find_nth_if(InputIterator first, InputIterator last, NthOccurence Nth, UnaryPredicate pred)
{
    if (Nth > 0)
        while (first != last) {
            if (pred(*first))
                if (!--Nth)
                    return first;
            ++first;
        }
    return last;
}

如果您绝对想要使用std::find_if,可以使用以下内容:

template<class InputIterator, class NthOccurence class UnaryPredicate>
InputIterator find_nth_if(InputIterator first, InputIterator last, NthOccurence Nth, UnaryPredicate pred)
{
    if (Nth > 0) {
        do
            first = std::find_if(first, last, pred);
        while (!--Nth && ++first != last);
        return first;
    }
    else
        return last;
}