C ++ 벡터의 요소를 요약하는 방법은 무엇입니까?


240

에서 모든 요소의 합을 찾는 좋은 방법은 무엇입니까 std::vector?

std::vector<int> vector요소가 몇 개 있는 벡터가 있다고 가정 합니다. 이제 모든 요소의 합계를 찾고 싶습니다. 동일한 방법은 무엇입니까?


1
"얼마나"? 정말? 지나치게 모호한 질문 인 것 같습니다. : p 좋은 방법을 찾는 것이 더 유용 할 수 있습니다.
jalf

3
"과 비슷한 기능"이라고 말할 때 무엇을 의미합니까? std::accumulateBoost 의 대체품을 찾고 있습니까? (그렇다면 왜 그런가?) 비슷한 기능을하는 함수를 찾고 std::accumulate있습니까? (그렇다면 무엇입니까?)
James McNellis

4
당신이 비슷한 것을 원한다면 std::accumulate, 아마도 당신은 또한 어떤면에서 다른 것을 원할 것입니다 (그렇지 않으면 그냥 사용할 수 있습니다 std::accumulate). std::accumulate찾고 있는 차이점 은 무엇입니까?
CB Bailey

답변:


429

실제로는 몇 가지 방법이 있습니다.

int sum_of_elems = 0;

C ++ 03

  1. 클래식 for 루프 :

    for(std::vector<int>::iterator it = vector.begin(); it != vector.end(); ++it)
        sum_of_elems += *it;
  2. 표준 알고리즘 사용 :

    #include <numeric>
    
    sum_of_elems = std::accumulate(vector.begin(), vector.end(), 0);

    중요 참고 : 마지막 인수의 유형은 초기 값 뿐만 아니라 결과 유형 에도 사용됩니다. 거기에 int를 넣으면 벡터가 플로팅 되어도 int가 누적됩니다. 당신은 부동 소수점 숫자, 변경 합산하는 경우 00.0또는 0.0f(nneonneo 덕분에). 아래의 C ++ 11 솔루션도 참조하십시오.

C ++ 11 이상

  1. 비. 향후 변경시에도 벡터 유형을 자동으로 추적합니다.

    #include <numeric>
    
    sum_of_elems = std::accumulate(vector.begin(), vector.end(),
                                   decltype(vector)::value_type(0));
  2. 사용 std::for_each:

    std::for_each(vector.begin(), vector.end(), [&] (int n) {
        sum_of_elems += n;
    });
  3. 범위 기반 for 루프 사용 (Roger Pate 덕분에) :

    for (auto& n : vector)
        sum_of_elems += n;

6
물론 C ++ 03 std::for_each에서는 functor와 함께 사용할 수 있으며 C ++ 0x 람다보다 정의하는 데 더 많은 코드 줄이 필요합니다.
Ben Voigt

8
람다 예제는 왜 사용 for_each합니까? accumulate더 간결 할 것입니다 (람다가 필요하지 않더라도)
jalf

4
@jalf : 당신의 요점은 맞습니다. accumulate내부에서 사용 했어야 for_each하지만이 예제는 (학습 목적으로) 유용하지 않습니다. 이것은 우리가 중첩 된 람다도 가질 수 있음을 보여줍니다 :-)
Prasoon Saurav

58
주의accumulate. 마지막 인수의 유형은 초기 값뿐만 아니라 결과 유형에도 사용됩니다. int거기에 넣으면 int벡터에가 있더라도 s 가 누적됩니다 float. 결과는 미묘하게 잘못 될 수 있으며 컴파일러는 사용자에게 알리지 않고 결과를 부동으로 다시 캐스팅합니다.
nneonneo 2019

3
for_each있다면 왜 사용 accumulate하겠습니까?
juanchopanza

46

가장 쉬운 방법은 다음을 사용 std:accumuate하는 것입니다 vector<int> A.

#include <numeric>
cout << accumulate(A.begin(), A.end(), 0);

34

Prasoon은 이미이 작업을 수행하기위한 여러 가지 (좋은) 방법을 제공했지만 여기서는 반복 할 필요가 없습니다. 그러나 속도에 대한 대체 접근법을 제안하고 싶습니다.

이 작업을 꽤 많이 수행하려는 경우 벡터의 "하위 분류"를 고려하여 요소의 합계가 별도로 유지되도록 할 수 있습니다 ( 실제로 하위 분류 벡터가 아님 ). 가상 소멸자 - 나는, 그 안에 합 벡터를 포함하는 클래스의 더 이야기하고 has-a대신를 is-a) 및 벡터와 같은 방법을 제공합니다.

빈 벡터의 경우 합계는 0으로 설정됩니다. 벡터에 삽입 할 때마다 합계에 삽입되는 요소를 추가하십시오. 삭제할 때마다 빼십시오. 기본적으로 합계를 일관되게 유지하기 위해 기본 벡터를 변경할 수있는 모든 항목 을 가로 챕니다.

이렇게하면 어느 시점에서든 합계를 "계산"할 수있는 매우 효율적인 O (1) 방법이 있습니다 (현재 계산 된 합계 만 반환). 총계를 조정할 때 삽입 및 삭제가 약간 더 오래 걸리므로이 성능 저하를 고려해야합니다.

합계를 계산하는 비용이 모든 액세스에 대해 상각되기 때문에 벡터가 변경되는 것보다 더 자주 합계가 필요한 벡터가이 체계의 이점을 얻을 수 있습니다. 분명히, 매 시간 합계 만 필요하고 벡터가 초당 3 천 번 변경되면 적합하지 않습니다.

이와 같은 것으로 충분합니다.

class UberVector:
    private Vector<int> vec
    private int sum

    public UberVector():
        vec = new Vector<int>()
        sum = 0

    public getSum():
        return sum

    public add (int val):
        rc = vec.add (val)
        if rc == OK:
            sum = sum + val
        return rc

    public delindex (int idx):
        val = 0
        if idx >= 0 and idx < vec.size:
            val = vec[idx]
        rc =  vec.delindex (idx)
        if rc == OK:
            sum = sum - val
        return rc

분명히, 그것은 의사 코드이며 약간 더 많은 기능을 원할 수도 있지만 기본 개념을 보여줍니다.


7
흥미롭지 만 std::vector서브 클래 싱 용이 아니므 로주의하십시오 .
Evan Teran

7
죄송합니다. 더 명확해야합니다 . has-a적절한 서브 클래스 ( is-a) 가 아니라 벡터 내에 벡터를 유지 한 vector 와 동일한 메서드를 사용하여 자신 만의 클래스를 만들 수 있습니다 .
paxdiablo

1
operator[](int)비 const 반복자 를 포함하여 데이터에 접근자를 비활성화하지 않는 한 문제가됩니다 ...
David Rodríguez-dribeas

1
@paxdiablo 나는 David가 벡터에 저장된 데이터가 operator []를 사용하거나 비 const 반복자를 통해 간접적으로 조작된다면 의미한다고 믿는다. 조작 된 위치의 값이 달라져 합계가 잘못됩니다. 클라이언트 코드가 "서브 클래스 된"벡터 내의 요소에 대해 변경 가능한 참조를 보유 할 수있는 경우 합계가 정확한지 확인할 방법이 없습니다.
Bret Kuhns

2
이 접근 방식은 기본 벡터 연산에 대한 성능 저하를 초래합니다.
Basilevs

23

합산을 뒤로 할 수 있는데 왜 합산을 수행 합니까? 주어진:

std::vector<int> v;     // vector to be summed
int sum_of_elements(0); // result of the summation

우리는 첨자를 사용할 수 있습니다.

for (int i(v.size()); i > 0; --i)
    sum_of_elements += v[i-1];

범위 검사 된 "첨자"를 사용할 수 있습니다.

for (int i(v.size()); i > 0; --i)
    sum_of_elements += v.at(i-1);

for 루프에서 역 반복자를 사용할 수 있습니다.

for(std::vector<int>::const_reverse_iterator i(v.rbegin()); i != v.rend(); ++i)
    sum_of_elements += *i;

for 루프에서 앞뒤로 반복하는 순방향 반복자를 사용할 수 있습니다 (oooh, 까다로운!) :

for(std::vector<int>::const_iterator i(v.end()); i != v.begin(); --i)
    sum_of_elements += *(i - 1);

우리는 accumulate역 반복자와 함께 사용할 수 있습니다 :

sum_of_elems = std::accumulate(v.rbegin(), v.rend(), 0);

for_each역 반복자를 사용하여 람다 식과 함께 사용할 수 있습니다 .

std::for_each(v.rbegin(), v.rend(), [&](int n) { sum_of_elements += n; });

보시다시피, 벡터 순방향을 합산하는 것만 큼 벡터를 역방향으로 합산하는 방법은 여러 가지가 있으며, 이들 중 일부는 훨씬 더 흥미롭고 일대일 오류에 대한 훨씬 더 큰 기회를 제공합니다.


36
랩 어라운드에 대한 계수 연산자로 소수를 추가하여 벡터를 순환하는 것이 어떻습니까? :-)
paxdiablo 5

3
@paxdiablo 당신은 정말로 상대적으로 소수만 필요합니다 v.size().
clstrfsck

1
-1 : vector :: size ()는 부호없는 값을 반환하여 (v.size ()-1)과 같은 표현식은 경고를 생성하거나 최악의 경우에는 마인 필드를 만듭니다.
Julien Guertault

1
이 답변이 존재하는 이유는 무엇입니까? 뒤로 합산하는 것이 유리합니까, 아니면 그냥 트롤링하고 있습니까?
Lynn

4
@Lynn : 벡터의 끝이 캐시에서 뜨거우면 (앞으로 가던 이전 루프에서) 예, 현재 인텔 x86 CPU에서 뒤로 루프하는 것이 훨씬 빠를 수 있습니다. 또한 루프 카운터를 0으로 카운트 다운하면 컴파일러가 명령을 asm에 저장할 수 있으며, 루프를 풀지 않으면 중요 할 수 있습니다. 프리 페치는 때때로 앞으로 루프 할 때 약간 더 잘 작동하므로 일반적으로 항상 뒤로 루프하는 것이 좋지 않습니다.
Peter Cordes

15
#include<boost/range/numeric.hpp>
int sum = boost::accumulate(vector, 0);

답변 해주셔서 감사합니다. BTW 시간 복잡성에서 std :: accumulate와 boost :: accumulate의 차이점은 무엇입니까?
Prasoon Saurav

1
시간 복잡도는 표준 및 부스트 누적에 대해 동일합니다. 이 경우 boost :: accumulate는 시작과 끝을 수동으로 보내는 것보다 입력하기가 쉽습니다. 실제 차이는 없습니다.
금속

7
boost::accumulate그냥 래퍼 std::accumulate입니다.
rafak

2
비 부스트 방법은 더 힘들어되지 않습니다 : #include <numeric>std::accumulate(v.begin(), v.end(), (int64_t)0);. 초기 누산기 값의 유형이 누산기 유형으로 사용되므로 8 비트 요소를 64 비트 결과로 합산하려면 그렇게해야합니다.
Peter Cordes

6

하나는 사용할 수있는 std::valarray<T>다음과 같은

#include<iostream>
#include<vector>
#include<valarray>

int main()
{
    std::vector<int> seq{ 1,2,3,4,5,6,7,8,9,10 };
    std::valarray<int> seq_add{ seq.data(), seq.size() };
    std::cout << "sum = " << seq_add.sum() << "\n";

    return 0;
}

벡터valarray 의 크기만큼 크기가 커야 하고 초기화하는 데 시간이 걸리기 때문에 일부는이 방법을 효율적으로 찾지 못할 수 있습니다 .valarray

이 경우에는 사용하지 말고 시퀀스를 요약하는 또 다른 방법으로 사용하십시오.


5

C ++ 0x 만 해당 :

vector<int> v; // and fill with data
int sum {}; // or = 0 ... :)
for (int n : v) sum += n;

이는 다른 곳에서 언급 된 BOOST_FOREACH와 유사하며, 누적 또는 for_each와 함께 사용되는 상태 저장 펑터와 비교하여 더 복잡한 상황에서도 명확성의 이점이 있습니다.


3
당신이 변경하는 경우 for (int n : v) sum += n;for (auto n : v) sum += n;그것은 어떤 벡터 템플릿과 함께 작동합니다. OP가 vector <int>를 참조하는 것으로 알고 있지만,이 방법은 약간 더 일반적입니다 :-)
Jonas

5

저는 Perl 사용자입니다. 우리가 가진 게임은 변수를 증가시키는 모든 다른 방법을 찾는 것입니다. C ++에서 벡터 요소의 합계를 찾는 방법에 대한 대답은 아마도 an infinity...

내 2 센트 :

BOOST_FOREACH를 사용하여 못생긴 반복자 구문을 제거하십시오.

sum = 0;
BOOST_FOREACH(int & x, myvector){
  sum += x;
}

인덱스 반복 (정말 읽기 쉽다).

int i, sum = 0;
for (i=0; i<myvector.size(); i++){
  sum += myvector[i];
}

이 다른 것은 스택처럼 벡터에 액세스하는 파괴적입니다.

while (!myvector.empty()){
   sum+=myvector.back();
   myvector.pop_back();
}

인덱스를 반복하는 것이 비효율적이라고 말하는 이유는 무엇입니까? 그 말의 근거는 무엇입니까?
bobobobo

@bobobobo : 글쎄요, 비효율적 일 것입니다. 벡터 및 증분 카운터에서 유효 데이터 위치를 계산해야하지만이 두 작업 중 하나이면 충분하지만 반복자를 역 참조하는 비용은 더 나쁠 수 있습니다. 그러므로 나는 그 단어를 제거 할 것입니다.
kriss

최적화 컴파일러는 인덱스 변수를 최적화하고 원하는 경우 포인터 증분을 사용할 수 있습니다. 루프 종료 조건을에 대한 포인터 비교로 만들 수 있습니다 start + length. 실제 반복자도 완전히 최적화해야합니다. 펄이 아니라는 것을 기억하십시오. 해석되지 않고 asm으로 완전히 컴파일됩니다.
Peter Cordes

-1

벡터의 모든 요소의 합을 찾는 가장 쉬운 방법을 찾았습니다.

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

int main()
{
    vector<int>v(10,1);
    int sum=0;
    for(int i=0;i<v.size();i++)
    {
        sum+=v[i];
    }
    cout<<sum<<endl;

}

이 프로그램에서는 크기가 10 인 벡터가 있고 1로 초기화됩니다. 배열처럼 간단한 루프로 합계를 계산했습니다.


1
inta를 색인하는 데 사용 하는 std::vector것은 일반적으로 안전하지 않습니다. v.size()는 저장할 수있는 가장 높은 값보다 클 수 있습니다 int(일부 대상 플랫폼 및 컴파일러에서는 size_of(int) < size_of(size_t)). 이 경우 코드에서 색인이 오버플로됩니다. std :: vector <T> :: size_type 을 선호해야합니다.
Vincent Saulue-Laborde

@ VincentSaulue-Laborde의 예입니다. 데이터 유형을 취할 수 있으며 요구 사항에 따라 크기가 다릅니다.
라비 Kumar Yadav

-5

쉽습니다. C ++ 11은 벡터 요소를 쉽게 요약 할 수있는 방법을 제공합니다.

sum = 0; 
vector<int> vec = {1,2,3,4,5,....}
for(auto i:vec) 
   sum+=i;
cout<<" The sum is :: "<<sum<<endl; 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.