2013-07-25 3 views

답변

12

예상 개수에 도달하면 인스턴스 수를 계산하고 완료 할 상태 저장 술어를 만들어야합니다. 이제 문제는 알고리즘을 평가하는 동안 술어가 복사되는 횟수에 대한 보장이 없다는 것입니다. 따라서 술어 그 자체를 외부에서 유지해야하기 때문에 추악합니다.하지만 그렇게 할 수는 있습니다. :이 자주오고, 성능에 대해 우려하지 않는 경우

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

+0

을 가치에 사로 잡힌 '가변적 인'람다도 마찬가지로 효과가 있습니까? – Yakk

+0

@Yakk : 아니요. 알고리즘의 구현은 술어를 복사 할 수있게되어 람다의 다른 인스턴스에서 카운트가 업데이트되고 결과적으로 알고리즘의 결과가 잘못 될 수 있습니다 (M -th, 여기서'M> N' 인스턴스) –

+0

@ DavidRodríguez-dribeas +1하지만 부스트 :: filter_iterator를 사용하면 좀 더 쉽게 접근 할 수 있습니다. 내 대답을 참조하십시오. – TemplateRex

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 (2 요소> 0, 1부터 시작 계산이 find_if 일치 n==1find_if_nth. 술어가 i > 10로 변경 또는 n 번째 요소가 n = 6로 변경하는 경우, 그것은 끝 반복자를 반환됩니다.

그래서

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을 사용하려는 경우, 당신은 같은 것을 할 수 : :

+0

[정의되지 않은 동작] (http://coliru.stacked-crooked.com/view?id=02ff2c799552600fb174b17d9eacd458-25783dc5e0579471d3e326cae35dc982) - [find_if_nth]와 일치 시키려면 더 신중하게 진행해야합니다 (http : //coliru.stacked- crooked.com/view?id=2d3e9b6357b3445aa30b374d6a149847-25783dc5e0579471d3e326cae35dc982).n 번째 요소가 존재하지 않는 경우 더 안전한 방법을 알고 계십니까? – Yakk

+0

경계 조건을 지적하기위한 @Yakk tnx. 정말로 그것에 대해 생각하지 않았다면 고칠 것입니다. – TemplateRex

+0

@Yakk 필자는 평소의'find_if'처럼 행동해야하는'find_if_nth'를 작성했고, 일치하는 n 번째 항목이 없을 때 end 반복자를 반환했습니다. 술어가'for' 루프에서 끌어 올려 졌기 때문에 여전히이 솔루션을 좋아합니다. – TemplateRex

3

STL과 같은 기능 템플릿이 될 것

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; 
} 
+0

eehm, 답변은 아직 사용자가 대답으로 표시되어 있습니다 ... – Manu343726

+0

@ Manu343726 : 나는 좋은 대답을 쓸 시간이 너무 많았습니다 :/게다가, 제 대답이 _ 대답보다 우수 할 수도 있습니다. .)) –

+0

나는 보통 너무 많은 시간을 들여 답을 썼다. 그리고 Im은 오랫동안 풀 설명 된 대답을 쓰고 있지만 수천 개의 두 줄의 답이 나옵니다. 나는 너를 이해한다 :) – Manu343726

관련 문제