2009-12-14 5 views
4

관심 클래스가 있습니다 (X라고 함).
나는 std :: list를 가지고있다. < X * > (그것을 L이라 부른다).
함수가 있습니다 (F라고 함).std :: list 및 std :: map에 대한 일반적인 알고리즘?

F (L)는 목록의 각 X의 내부 상태를 검사하는 알고리즘에 따라 L (하위 목록 : <X * >)의 하위 집합을 반환합니다.

나는, X * > (그것을 M 전화)지도를 :: 내 응용 프로그램에 < 지능 성병을 추가 해요, 난 F (M)는 같은 방식으로 작동하도록 정의 할 필요가 같은 F (L) - 그 다시 말해, F (M)는지도에서 각 X의 내부 상태를 조사하여 결정된 표준 : : < X * >을 반환해야합니다.

자체 기술 된 게으른 프로그래머이므로, 알고리즘이 [논리적으로] 같고 각 데이터 형식 (std :: list 및 std :: map)이 반복 가능한 템플릿이라는 것을 알았습니다. 같은 알고리즘을 두 번 이상 유지하고 싶지는 않지만 앞으로 나아갈 방법이 확실하지 않습니다.

하나의 접근법은 F (M) (즉, 키 - 값 맵의 'values')에서 X *를 가져 와서 std :: list < X * >에 던져 넣는 것입니다. F (std :: list < X * >)에 처리를 보냅니다. return std :: list를 전달합니다. < X * >; 다시 통해. 어떻게 이것이 유일한 길인지 나는 알 수 없다.

내 질문 : 어떻게 한 곳에서 핵심 알고리즘을 유지할 수 있지만 시퀀스 또는 쌍 연관 컨테이너의 값을 반복 할 수 있습니까?

감사합니다.

답변

7

첫째, 모든 std::remove_copy_if 수행 할 수 있습니다 : 같은 것에 대해 어떻게

+0

펑터가 정말 간결하기 때문에 나는 이것을 좋아한다. Mic와 Anon과 같은 아이디어. 하지만 나는 가장 우아하다고 생각합니다. 감사! –

+0

@Chris - 동의합니다. remove_copy_if가 저 자신 (이상한 이름 지정)처럼 행동했는지는 몰랐습니다. 분명히 그것을 내 무기고에 추가 할 것입니다. :). – Mic

0

한 가지 해결책은 두 함수에서 알고리즘을 이동하는 것입니다.이 함수는 해당 컨테이너를 반복하고 algo 함수를 호출하여 특정 항목이 반환 목록에 속하는지 여부를 결정합니다.

2

두 개의 전달 반복자를 매개 변수 (시작과 끝)로 허용하는 함수를 작성하면 함수는 반복기의 값을 테스트하고 테스트를 통과하면 목록에 추가하며 반복기를 증가시키고 테스트합니다 끝까지 도달하지 못한다. (깨지면 깨진다.)

그런 다음 함수를 호출하고 컬렉션의 begin() 및 end() 반복자를 전달한다.

+0

그러나 앞으로 반복자는 성병 :: 목록은 표준 : :지도 반복자 역 참조 반면 표준에 :: 쌍,

+1

@ 크리스 진정한는 X * 직접 dereferenceable이지만, 단지 키를 통해 반복의 방법이 있습니다 또는 쌍 대신지도의 값을 지정합니다. http://stackoverflow.com/questions/1443793/iterate-keys-in-ac-map 및 http://stackoverflow.com/questions/259240/iterator-adapter-to-iterate-just-the-values-in을 참조하십시오. -a-map – csj

0

아마도 제안한 방법이 유일한 해결책은 아니지만 올바르게 작성하고 이해하는 것이 가장 쉬운 방법 일 것입니다. 프로덕션 코드를 작성한다면 확실히 시작할 것입니다. 필요한 경우에만 코드 프로파일을 작성하고 좋아하는 사람에게 알리십시오.

다른 옵션을 살펴 보려면 boost::bind을 살펴보십시오. 나는 비슷한 것을 다시하려고 할 때 this answer을 받았다. 그리고 나는 std::tr1::bind이 기본적으로 동일하다고 생각합니다. 따라서 Boost가없는 경우 TR1 버전을 대체 할 수 있어야합니다. 모두 조건 만

template<typename T> 
struct func { 
    std::list<T>& r; 
    func(std::list<T>& r_) : r(r_) {} 

    bool algorithm(const T& t) { 
     return t<5; // obviously meant to be replaced :) 
    } 

    void operator()(const T& t) { 
     if (algorithm(t)) r.push_back(t); 
    } 

    void operator()(const std::pair<int, T>& t) { 
     if (algorithm(t.second)) r.push_back(t.second); 
    } 

}; 

template<typename T, typename ForwardIterator> 
std::list<T> subset(ForwardIterator begin, ForwardIterator end) { 
    std::list<T> r; 
    std::for_each(begin, end, func<T>(r)); 
    return r; 
} 
1

. remove_copy_if이라는 이름에도 불구하고 원래 컬렉션에서 아무 것도 제거하지 않습니다.사람들이 filtered_copy과 같은 이름이라면 사람들이 더 쉽게 이해할 수있을 것입니다. 컬렉션간에 요소를 복사합니다. 각 요소에 대해 술어를 호출하고 술어가 해당 요소에 대해 false를 리턴하는 경우에만 항목이 복사됩니다.

이렇게하면 단 하나의 책임 만 남게됩니다. 각 X *를 살펴보고 테스트 함수를 구현하여 작성중인 복사본에서 제외해야하는지 여부를 말합니다. 논리의 한 조각이 두 가지 다른 방식으로 적용되기를 원하기 때문에 논리를 클래스의 전용 함수로 캡슐화합니다. 그 다음 클래스에 대한 operator()의 오버로드 된 버전으로 외부 세계에 공급 될 수있는 두 가지 방법 : operator()(X const *) 이후

class F { 
    bool do_test(X const *x) const { return x.internal_stuff; } 
public: 
    bool operator()(X const *x) const { return do_test(x); } 

    bool operator()(std::pair<int, X const *> const &p) const { 
     return do_test(p.second); 
    } 
}; 

do_test()에 순수 썽크입니다, 당신은 그 것 IMO 그것을 제거하기를 원하지만 수 아마 좋은 것보다 해를 끼치십시오.

어쨌든 로직을 완전히 한 곳 (F::do_test)에 남겨 둡니다. 또한 중 하나 list<X *>의 필터링 된 사본 또는 std::map<int, X *>을 만들기위한 간단하고 일관성있는 구문을 제공 : 최종 참고로

std::list<X *> result; 
std::remove_copy_if(coll.begin(), coll.end(), std:back_inserter(result), F()); 

을 : std::list 아마 현존하는 가장 이상 사용하는 모음입니다. 그것의 용도가있는 동안, 그들은 진짜로 아주 희소하다. std::vectorstd::deque매우 자주입니다.

관련 문제