C ++ベクトルの要素を合計する方法は?


240

のすべての要素の合計を見つける良い方法は何std::vectorですか?

std::vector<int> vectorいくつかの要素を含むベクトルがあるとします。次に、すべての要素の合計を求めます。同じための異なる方法は何ですか?


1
"幾つ"?本当に?それは過度にあいまいな質問のようです。:p それを行うための良い方法を尋ねる方が便利かもしれません。
10

3
「似た機能」とはどういう意味ですか?std::accumulateBoostの代替品をお探しですか?(もしそうなら、なぜですか?)に似た機能を実行する関数を探していstd::accumulateますか?(もしそうなら、何ですか?)
ジェームズ・マクネリス10/07/13

4
に似たものが必要な場合はstd::accumulate、おそらくそれを何らかの点で異なるものにしたいと思うでしょう(そうでなければ、単にを使用することもできますstd::accumulate)。std::accumulateあなたが探しているものとの違いは何ですか?
CBベイリー

回答:


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を累積します。浮動小数点数を合計する場合は、またはに変更0します(nneonneoに感謝します)。以下のC ++ 11ソリューションも参照してください。0.00.0f

C ++ 11以降

  1. b。将来変更があった場合でも、ベクトルタイプを自動的に追跡します。

    #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ファンクターを使用できます。C++ 0xラムダよりも、定義するコードの行数が多くなります。
Ben Voigt

8
なぜラムダの例は使用するのfor_eachですか?accumulate(ラムダが必要ない場合でも)より簡潔になります
jalf

4
@jalf:あなたのポイントは、私が使用している必要があり、正確であるaccumulate内部をfor_each、それが:-)我々はまた、ネストされたラムダを持つことができることを示すよう(目的を学ぶために)便利なこの例ではありません
Prasoon Saurav

58
に注意してくださいaccumulate。最後の引数の型は、初期値だけでなく、結果の型にも使用されます。intそこに置くとint、ベクトルが持っていてもs がたまりますfloat。結果は微妙に間違っている可能性があり、コンパイラは通知せずに結果を浮動小数点数にキャストします。
nneonneo 2013

3
for_eachあなたが持っているならなぜあなたは使うのaccumulateですか?
juanchopanza

46

最も簡単な方法は、使用することですstd:accumuatevector<int> A

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

34

Prasoonはこれを行うためのさまざまな(そして良い)方法をすでに提供していますが、ここで繰り返す必要はありません。ただし、速度の代替アプローチを提案したいと思います。

これをかなり行う場合は、要素の合計が個別に維持されるように、ベクトルを「サブクラス化」することを検討することをお勧めします(実際のサブクラス化ベクトルではなく、仮想デストラクタ-私は、has-aではなく、和とその中のベクトルを含みis-a、ベクトルのようなメソッドを提供するクラスのことを話しています。

空のベクトルの場合、合計はゼロに設定されます。ベクトルに挿入するたびに、挿入する要素を合計に追加します。すべての削除で、それを引きます。基本的に、基になるベクトルを変更する可能性があるものはすべて遮断され、合計の一貫性が保たれます。

このように、任意の時点で合計を「計算」するための非常に効率的なO(1)メソッドがあります(現在計算されている合計を返すだけです)。合計を調整すると、挿入と削除に若干時間がかかります。このパフォーマンスヒットを考慮する必要があります。

ベクトルが変更されるよりも頻繁に合計が必要とされるベクトルは、合計を計算するコストがすべてのアクセスにわたって償却されるため、このスキームから恩恵を受ける可能性が高いベクトルです。明らかに、1時間ごとに合計が必要なだけで、ベクトルが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、サブクラス化用ではないので注意してください。
エヴァンテラン2010

7
申し訳ありませんが、私はより明確である必要がありました- has-a適切なサブクラス(is-a)ではなく、ベクターを維持するベクターと同じメソッドで独自のクラスを作成できます。
paxdiablo

1
あなたがこれらに限定されないが、データへのアクセサを無効にしない限り、これは問題であるoperator[](int)非constイテレータ...、
dribeas -デビッド・ロドリゲス

1
@paxdiablo Davidは、ベクターに格納されたデータが、operator []を使用するか、非constイテレーターを介して間接的に操作されるかどうかを意味すると信じています。操作した位置の値が異なるため、合計が不正確になります。クライアントコードが「サブクラス化された」ベクトル内の任意の要素への可変参照を保持できる場合、合計が正しいことを保証する方法はありません。
Bret Kuhns、2012

2
この方法では、基本的なベクトル演算のパフォーマンスが低下します。
バシレフ2012

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ループで前方反復子、後方反復子を使用できます(ああ、トリッキーです!):

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; });

ご覧のとおり、ベクトルを逆方向​​に合計する方法は、ベクトルを順方向に合計する方法と同じくらい多くあり、これらのいくつかははるかにエキサイティングで、off-by-oneエラーのはるかに大きな機会を提供します。


36
そして、ラップアラウンド用のモジュラス演算子を使って素数を追加することにより、ベクトルを循環させてみませんか?:-)
paxdiablo 2010

3
@paxdiabloあなたは本当に本当に比較的素数である必要がありますv.size()
clstrfsck 2010

1
-1:vector :: size()は符号なしの値を返し、(v.size()-1)のような式が警告を生成するか、最悪の場合は地雷原を生成します。
Julien Guertault、2014

1
なぜこの答えが存在するのですか?逆に合計することの利点はありますか、それとも単なるトローリングですか?
Lynn

4
@Lynn:ベクターの最後がキャッシュ内でホットになっている場合(前に進んだループから)、はい、現在のIntel x86 CPUでは逆方向のループがかなり高速になる可能性があります。また、ループカウンターをゼロにカウントすると、コンパイラーがasm内の命令を節約できます。これは、ループを展開しない場合に重要になる可能性があります。ただし、順方向にループする場合は、プリフェッチがわずかにうまく機能することがあります。そのため、通常は常に逆方向にループする方が良いとは限りません。
Peter Cordes 2017

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

答えてくれてありがとう。ところで、時間の複雑さにおけるstd :: accumulateとboost :: accumulateの違いは何ですか?
Prasoon Saurav 2010

1
時間の複雑さはstdとboostの累算で同じです-線形。この場合、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に似ており、accumulateまたは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 2010

@bobobobo:まあ、非効率はおそらく過剰です。ベクトルとインクリメントカウンターの両方から有効なデータ位置を計算する必要がありますが、これら2つの演算のいずれかで十分ですが、反復子の逆参照のコストはさらに悪化する可能性があります。したがって、その単語を削除します。
クリス、

最適化コンパイラは、インデックス変数を最適化し、必要に応じてポインタのインクリメントを使用できます。(ループ終了条件をとのポインタ比較にすることができますstart + length)。実際のイテレータも完全に最適化する必要があります。覚えておいてください、それはperlではありません。完全に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
intインデックスに使用することstd::vectorは、一般的に安全ではありません。v.size()に格納できる最大値よりも大きい場合がありますint(一部のターゲットプラットフォームおよびコンパイラでは、size_of(int) < size_of(size_t))。この場合、コードはインデックスをオーバーフローします。std :: vector <T> :: size_typeをお勧めします。
Vincent Saulue-Laborde

それは例です@ VincentSaulue-Labordeあなたはデータ型を取ることができ、それはあなたの要件に応じたサイズです。
Ravi 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.