2009-08-25 2 views
10

for_each에 의해 허용되는 함수는 하나의 매개 변수 (벡터의 요소) 만 사용하므로 for_each를 호출 한 후 에 액세스 할 수 있도록 어딘가에 static int sum = 0을 정의해야합니다. . 나는 이것이 어색하다고 생각한다. 이것을 수행하는 더 좋은 방법 (여전히 for_each 사용)?for_each를 사용하여 벡터의 각 요소의 제곱의 합

sum = 0 
[1,2,3,4].each { |i| sum += i*i} #local variable can be used in the callback function 
puts sum #=> 30 

당신이 for_each는 일반적으로 (다만 각 요소를 인쇄하지 않음) 실제 프로그래밍에서 사용되는 방법을 더 예를 보여 주시겠습니까 :

루비에서
#include <algorithm> 
#include <vector> 
#include <iostream> 

using namespace std; 

static int sum = 0; 
void add_f(int i) 
{ 
    sum += i * i; 

} 
void test_using_for_each() 
{ 
    int arr[] = {1,2,3,4}; 
    vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0])); 

    for_each(a.begin(),a.end(), add_f); 
    cout << "sum of the square of the element is " << sum << endl; 
} 

, 우리는 이런 식으로 할 수 있습니까?for_each을 사용하여지도와 같은 '프로그래밍 패턴'을 시뮬레이션하고 Ruby (또는 Haskell의지도/접기)에 삽입 할 수 있습니까?

#map in ruby 
>> [1,2,3,4].map {|i| i*i} 
=> [1, 4, 9, 16] 

#inject in ruby 
[1, 4, 9, 16].inject(0) {|aac ,i| aac +=i} #=> 30 

편집 : 고맙습니다. 당신의 답장에서 나는 많은 것을 배웠습니다. 우리는 C++에서 똑같은 일을하는 방법이 너무 많아서 배우기가 조금 어렵습니다. 그러나이 흥미로운 :)

답변

18

사용 std::accumulate

#include <vector> 
#include <numeric> 

// functor for getting sum of previous result and square of current element 
template<typename T> 
struct square 
{ 
    T operator()(const T& Left, const T& Right) const 
    { 
     return (Left + Right*Right); 
    } 
}; 

void main() 
{ 
    std::vector <int> v1; 
    v1.push_back(1); 
    v1.push_back(2); 
    v1.push_back(3); 
    v1.push_back(4); 

    int x = std::accumulate(v1.begin(), v1.end(), 0, square<int>()); 
    // 0 stands here for initial value to which each element is in turn combined with 
    // for our case must be 0. 
} 

당신은 표준 모방 수를 :: nice GMan's answer 같이 축적하지만, 위해 설계 되었기 때문에 나는 표준 : 축적를 사용하여 코드를 읽기 쉽게 만들 것이라고 믿는다 그러한 목적. 더 많은 표준 알고리즘 here을 찾을 수 있습니다.

+1

벡터 반복기가 std 네임 스페이스에 있음을 보장하지는 않습니다. 그것이 맞다면 ADL은 여기서 작동하는 것이 보장되지 않으며 질문자는 컴파일러를 지정하지 않았습니다. –

+2

네 말이 맞아. 방금 확인했습니다. 표준은 반복기가 std 네임 스페이스의 일부임을 보장하지 않습니다. 역방향 이터레이터 만'std' 네임 스페이스의 일부입니다. –

+0

onebyone : 와우, 잘 잡으세요. 나는 표준을 검사했고 당신은 절대적으로 옳다. 그래서 예. 벡터 :: iterator가 T *에 typedefed되면 ADL이 실제로 실패합니다. OP의 관심을 얻으려고 -100 ... (게시물은 다른 점은 그다지 우수하지 않습니다.) –

7

for_each은 사용중인 펑터를 반환합니다. 그래서,이 같은 :

#include <algorithm> 
#include <vector> 
#include <iostream> 

template <typename T> 
class square_accumulate 
{ 
public: 
    square_accumulate(void) : 
     _sum(0) 
     { 
     } 

     const T& result(void) const 
     { 
      return _sum; 
     } 

     void operator()(const T& val) 
     { 
      _sum += val * val; 
     } 

private: 
    T _sum; 
}; 

int main(void) 
{ 
    int arr[] = {1,2,3,4}; 
    std::vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0])); 

    int sum = std::for_each(a.begin(), a.end(), square_accumulate<int>()).result(); 

    std::cout << "sum of the square of the element is " << sum << std::endl; 
} 

다른 답변에서 보듯이,하지만, std::accumulate 갈 수있는 가장 좋은 방법입니다.

+0

+1, 나는 생각하지 않았다. –

+3

이것은 std :: accumulate 에뮬레이션의 좋은 샘플입니다. 가르치는 목적에 유용합니다. –

+0

아래로 투표 의견? 내가 뭘 잘못했는지 알 수 없다면 개선 할 수는 없다. – GManNickG

3

STL에서 이러한 문제를 해결하는 일반적인 방법은 함수를 전달하는 대신 functor (예 : operator()을 구현하는 모든 클래스의 인스턴스)을 전달하는 것입니다. 이것은 인스턴스가 자신의 상태를 유지하고 업데이트 할 수 있기 때문에 전역 변수에 의존하는 것보다 훨씬 낫습니다! 당신은 일종의 "컴파일 타임 오리 타이핑 (dile typing)"이라고 생각할 수 있습니다 : 일반적인 프로그래밍은 "함수처럼 행동하는"(즉, 적절한 operator()을 가진) 그 곳에서 "함수"를 전달하도록 제한하지 않습니다 뿐만 아니라 -)

3

<numeric> 헤더 accumulate()을 사용하여, 이에 대한 for_each()을 사용하지 마십시오!

#include <numeric> 
#include <iostream> 
using namespace std; 

struct accum_sum_of_squares { 
    // x contains the sum-of-squares so far, y is the next value. 
    int operator()(int x, int y) const { 
     return x + y * y; 
    } 
}; 

int main(int argc, char **argv) { 
    int a[] = { 4, 5, 6, 7 }; 

    int ssq = accumulate(a, a + sizeof a/sizeof a[0], 0, accum_sum_of_squares()); 
    cout << ssq << endl; 
    return 0; 
} 

accumulate()의 디폴트의 동작은, 요소를 요약하는 것입니다,하지만 당신은 자신의 함수 나 펑터를 제공 할 수 있습니다 우리가 여기에서하는 것처럼, 그리고 그것이 수행하는 연산은 연관 될 필요가 없다 - 두 번째 인수는 항상 연산 될 다음 요소이다. 다른 언어에서는이 조작을 reduce라고도합니다.

accum_sum_of_squares 펑터 대신 일반 함수를 사용하거나 더 일반적인 경우 accum_sum_of_squares을 모든 숫자 유형을 허용하는 클래스 템플릿으로 만들 수 있습니다.

32

아니요, std :: accumulate()를 사용하지 마십시오. std :: inner_product()를 사용하십시오. 펑터 필요 없음.

#include <vector> 
#include <numeric> 

void main() 
{ 
    std::vector <int> v1; 
    v1.push_back(1); 
    v1.push_back(2); 
    v1.push_back(3); 
    v1.push_back(4); 

    int x = std::inner_product(v1.begin(), v1.end(), v1.begin(), 0); 
} 
+0

매우 우아하고 ... 정확히 내가 찾고 있던 것! – Jacob

+3

왜 이것이 최상위 답변이 아닙니까? – math

3

std::for_each 요소와 일을위한 것입니다. 의 계산 결과를 모두 얻으려면 요소가 있고 std::accumulate입니다. Haskell의 map 동작을 원하면 std::transform을 사용하십시오.

두 개의 반복자를 입력으로 사용하는 transform의 양식을 제외하고는 반복자를 반복적으로 수행하기 때문에 나머지 세 개 중 하나와 동일한 작업을 수행 할 수 있습니다. 요점은 for_each는 map/fold를 대신 할 수있는 것이 아닙니다. transform/accumulate에 의해 수행되어야합니다. C++은 Haskell뿐만 아니라 map/fold 개념을 표현하지 않습니다. 그러나 gcc와 VC++ 모두 OpenMP를 지원합니다. #pragma omp parallel for에서 훨씬 더 좋은 아날로그입니다.

루비에서 주입은 위에서 설명한 GMan과 같은 본격적인 기능기를 사용하여 for_each을 호출하는 것에 훨씬 더 근접합니다. C++ 0X에서 가변 캡처를 사용하는 람다 함수는 두 언어 간의 동작을 훨씬 더 유사하게 만듭니다.

int main(void) 
{ 
    int arr[] = {1,2,3,4}; 
    std::vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0])); 

    int sum = 0; 
    std::for_each(a.begin(), a.end(), [&](int i) { sum += i*i;}); 

    std::cout << "sum of the square of the element is " << sum << std::endl; 
} 
+1

은 sum + = i * i가되어야합니다. – mskfisher