如何总结一个c++向量的元素?

找到std::vector中所有元素的和的方法是什么?

假设我有一个向量std::vector<int> vector,其中有几个元素。现在我要求所有元素的和。同样的东西有什么不同的表达方式?

510583 次浏览

实际上有相当多的方法。

int sum_of_elems = 0;

c++ 03

  1. 经典循环:

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

    重要提示:最后一个参数的类型不仅用于初始值,也用于结果的类型。如果你在这里输入一个整型,它会累积整型,即使这个向量是浮点数。如果要对浮点数求和,请将0改为0.00.0f (感谢nneonneo)。请参见下面的c++ 11解决方案。

c++ 11及以上版本

  1. < p > b。自动跟踪vector类型,即使将来发生更改:

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

     std::for_each(vector.begin(), vector.end(), [&] (int n) {
    sum_of_elems += n;
    });
    
  3. 使用基于范围的for循环(多亏了罗杰·佩特):

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

c++ 17及以上版本

  1. 使用std::reduce,它也关心结果类型,例如,如果你有std::vector<int>,你会得到int作为结果。如果你有std::vector<float>,你会得到float。或者如果你有std::vector<std::string>,你得到std::string(所有字符串连接)。很有趣,不是吗?

    auto result = std::reduce(v.begin(), v.end());
    

    此函数的其他重载,你甚至可以并行运行,如果你有一个大的集合,你想快速得到结果。

我是一个Perl用户,我们有一个游戏是找到各种不同的方法来增加一个变量…这里没有什么不同。在c++中,有多少种方法可以找到向量元素的和,答案可能是an infinity

我的观点是:

使用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];
}

另一个是破坏性的,像访问堆栈一样访问vector:

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

prason已经提供了许多不同的(而且很好的)方法来做到这一点,这里没有一个需要重复。不过,我想建议另一种提高速度的方法。

如果你要经常这样做,你可能想要考虑“子类化”你的vector,这样元素的和就被分开维护(不是实际上子类化vector,因为缺少虚析构函数而存在问题——我更多地谈论的是一个包含和和和其中的vector的类,has-a而不是is-a,并提供类vector方法)。

对于空向量,和设为零。每次插入向量时,将插入的元素加到和中。在每次删除时,减去它。基本上,可以改变底层向量的任何东西将被拦截,以确保总和保持一致。

这样,您就有了一个非常有效的O(1)方法来“计算”任何时间点的和(只返回当前计算的和)。插入和删除将花费稍长的时间来调整总数,您应该考虑到这种性能影响。

如果向量的和比向量的改变更频繁,那么这些向量可能会从这个方案中受益,因为计算和的成本会在所有访问中摊销。显然,如果你只需要每小时求和,而向量每秒变化3000次,这是不合适的。

这样就足够了:

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

显然,这是伪代码,您可能希望有更多的功能,但它显示了基本概念。

为什么执行求和向前当你可以做向后?考虑到:

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与lambda表达式一起使用:

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

所以,正如你所看到的,向后求和的方法和正向求和的方法一样多,其中一些更令人兴奋,并且提供了更大的机会出现差1的错误。

c++ 0 x只:

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

这类似于其他地方提到的BOOST_FOREACH,与与accumulate或for_each一起使用的有状态函子相比,在更复杂的情况下具有同样的清晰性。

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

也可以像这样使用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也需要时间。

在这种情况下,不要使用它,把它作为另一种对序列求和的方式。

最简单的方法是使用vector<int> Astd:accumulate:

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

这很简单。c++ 11提供了一种简单的方法来对一个向量的元素求和。

sum = 0;
vector<int> vec = {1,2,3,4,5,....}
for(auto i:vec)
sum+=i;
cout<<" The sum is :: "<<sum<<endl;
 #include<iostream>
#include<vector>
#include<numeric>
using namespace std;
int main() {
vector<int> v = {2,7,6,10};
cout<<"Sum of all the elements are:"<<endl;
cout<<accumulate(v.begin(),v.end(),0);
}

似乎没有人能解决向量中可以有NaN值的元素求和的情况,例如numerical_limits<double>::quite_NaN()

我通常会遍历元素并直接检查。

vector<double> x;


//...


size_t n = x.size();


double sum = 0;


for (size_t i = 0; i < n; i++){


sum += (x[i] == x[i] ? x[i] : 0);


}

它一点都不花哨,也就是说,没有迭代器或任何其他技巧,但我是这样做的。有时,如果在循环中有其他事情要做,我想让代码更具可读性,我就写

double val = x[i];


sum += (val == val ? val : 0);


//...

并在需要时重用val

使用inclinclve_scan (c++ 17及以上):

好处是你可以得到第一个“n”的总和;向量中的元素。下面是代码。在评论中解释。

要使用inclusive_scan,需要包含"数字"头。

    //INPUT VECTOR
std::vector<int> data{ 3, 1, 4, 1, 5, 9, 2, 6 };


//OUTPUT VECTOR WITH SUMS
//FIRST ELEMENT - 3
//SECOND ELEMENT - 3 + 1
//THIRD ELEMENT - 3 + 1 + 4
//FOURTH ELEMENT - 3 + 1 + 4 + 1
// ..
// ..
//LAST ELEMENT - 3 + 1 + 4 + 1 + 5 + 9 + 2 + 6
std::vector<int> sums(data.size());


//SUM ALL NUMBERS IN A GIVEN VECTOR.
inclusive_scan(data.begin(), data.end(),
sums.begin());


//SUM OF FIRST 5 ELEMENTS.
std::cout << "Sum of first 5 elements :: " << sums[4] << std::endl;


//SUM OF ALL ELEMENTS
std::cout << "Sum of all elements :: " << sums[data.size() - 1] << std::endl;

还有一种重载,可以指定执行策略。顺序执行或并行执行。需要包括“执行”;头。

    //SUM ALL NUMBERS IN A GIVEN VECTOR.
inclusive_scan(std::execution::par,data.begin(), data.end(),
sums.begin());

使用reduce:

我在答案中没有注意到的另一个选项是使用c++17中引入的std::reduce

但是你可能会注意到很多编译器不支持它(GCC 10以上可能就不错了)。但最终支持会来的。

使用std::reduce,优势体现在使用执行策略时。指定执行策略可选。当指定的执行策略为std::execution::par时,算法可以使用硬件并行处理功能。当使用大尺寸向量时,增益可能会更明显。

例子:

//SAMPLE
std::vector<int> vec = {2,4,6,8,10,12,14,16,18};
    

//WITHOUT EXECUTION POLICY
int sum = std::reduce(vec.begin(),vec.end());
    

//TAKING THE ADVANTAGE OF EXECUTION POLICIES
int sum2 = std::reduce(std::execution::par,vec.begin(),vec.end());
    

std::cout << "Without execution policy  " << sum << std::endl;
std::cout << "With execution policy  " << sum2 << std::endl;
std::reduce需要<numeric>报头。 和'<execution>'用于执行策略

std::accumulate可能有溢出问题,所以最好的方法是对更大的数据类型变量进行基于范围的积累,以避免溢出问题。

long long sum = 0;
for (const auto &n : vector)
sum += n;

然后向下转换为适当的数据类型,进一步使用static_cast<>