I'm trying to sum the values of a vector but I have a problem with that.
The size of the vector is 20 elements and I'm trying to do a sum of 5 elements from the current position.
Something like: sum the elements from 1 to 5, 2 to 6, 3 to 7 and so on.
I thought that I could do a for nested loop, like this one below:
for (int a = 0; a < numVec.size(); a ) {
for (int b = a; b < numVec.size(); b )
{
if (aux < 5) {
cout << "B: " << b << endl;
sum = numVec[b].num;
}
if (aux > 4) {
aux = 0;
sumAux= sum;
sum= 0;
break;
}
aux ;
}
cout << "Sum: " << sumAux<< endl;
}
But I'm having some problems when I get the 15th position, everything goes wrong and I can't figure out why.
If you can help me, I thank you very much.
CodePudding user response:
It will help you a lot, if you think for a longer time before start to code something. Maybe you can take a piece of paper and write something down.
Then, it will very much help you, if you choose long and speaking variable names.
So, let us make a picuture. We write some test values and their index in the vector, where they are stored. Please remeber. Indices start with 0 in C .
Value: 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
Index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
So, and if we now want to build the sums for 5 values each, then we need to add
Index 0 1 2 3 4 Value: 21 22 23 24 25
Index 1 2 3 4 5 Value: 22 23 24 25 26
Index 2 3 4 5 6 Value: 23 24 25 26 27
. . .
Index 14 15 16 17 18 Value: 35 36 37 38 39
Index 15 16 17 18 19 Value: 36 37 38 39 40
So, you can see. We have a start index that always will be incremented by 1. Beginning with this start index, we will always add up 5 values. But we must end this process, as you can see above at index 15, so 20 - 5.So, always, size of the whole array - the size of the subarray.
So, let us first solve this problem we can do it strigh forward:
#include <iostream>
#include <vector>
int main() {
// Our test data to play with
std::vector<int> data = { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40 };
// This is the size of the subarray. So the number of values that we want to sum up
int sizeOfSubarray = 5;
// And because we have a subarray size, the last summation starts at this index
int lastIndex = data.size() - sizeOfSubarray;
// So, now iterate over all data that needs to be summed up
for (int startIndex = 0; startIndex <= lastIndex; startIndex) {
// Because we have a new start index now, we start also with a 0 sum
int sum = 0;
// Calculate the end index of the sub array
int endIndexOfSubarray = startIndex sizeOfSubarray;
for (int sumIndex = startIndex; sumIndex < endIndexOfSubarray; sumIndex) {
// Some debug output
std::cout << "Startindex: " << startIndex << "\tSumindex: " << sumIndex << "\tValue: " << data[sumIndex] << '\n';
// Calculate the subarray sum
sum = sum data[sumIndex];
}
// Show the subarray sum
std::cout << "Sum: " << sum << '\n';
}
}
OK, understood. What, if we want also to add up the end of the values of the array? So, what if the startindex will rund over the complete array. Let us look at this.
Index 16 17 18 19 ? Value: 37 38 39 40 ?
Index 17 18 19 ? ? Value: 38 39 40 ? ?
Index 18 19 ? ? ? Value: 39 40 ? ? ?
Index 19 ? ? ? ? Value: 40 ? ? ? ?
You can see, that the start index runs until < 20. So < size of vector.
And if the is the end index of the summation is > 19, so >= the sizeof the vector, we can limit it to 19,
This we can either calculate or use a simple if statement.
Then the code would look like that
#include <iostream>
#include <vector>
int main() {
// Our test data to play with
std::vector<int> data = { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40 };
// This is the size of the subarray. So the number of values that we want to sum up
int sizeOfSubarray = 5;
// So, now iterate over all data that needs to be summed up
for (int startIndex = 0; startIndex < data.size(); startIndex) {
// Because we have a new start index now, we start also with a 0 sum
int sum = 0;
// Calculate the end index of the sub array
int endIndexOfSubarray = startIndex sizeOfSubarray;
// If this index is too big ( > 20) then limit it to 20
if (endIndexOfSubarray > data.size()) {
endIndexOfSubarray = data.size();
}
// Claculate sum of sub array
for (int sumIndex = startIndex; sumIndex < endIndexOfSubarray; sumIndex) {
// Some debug output
std::cout << "Startindex: " << startIndex << "\tSumindex: " << sumIndex << "\tValue: " << data[sumIndex] << '\n';
// Calculate the subarray sum
sum = sum data[sumIndex];
}
// Show the subarray sum
std::cout << "Sum: " << sum << '\n';
}
}
I hope, this explanation helps
CodePudding user response:
One option is to have the inner loop range from 0-5
for (int a = 0; a < numVec.size(); a ) {
int sum = 0;
for (int b = 0; b < 5 && a b < numVec.size(); b ) {
sum = numVec[a b];
}
std::cout << sum << "\n";
}
Another option is to use std::accumulate
for (auto a = numVec.begin(); a < numVec.end(); a ) {
std::cout << std::accumulate(a, std::min(a 5, numVec.end()), 0) << '\n';
}
Also, mentioned in the comments by @Bathsheba is to keep a running total, which is O(n).
int sum = 0;
for (int a = 0; a < 5 && a < numVec.size(); a ) sum = numVec[a];
std::cout << sum << '\n';
for (int a = 5; a < numVec.size(); a ) {
sum = sum - numVec[a - 5] numVec[a];
std::cout << sum << '\n';
}
CodePudding user response:
This is considered to be the rolling sum etc. You could write a template that manipulates a binary function on the vector specifying the window:
# include <iostream>
# include <numeric>
# include <vector>
# include <functional>
using namespace std;
template<class T, class Lambda>
vector<T> roll_fun(vector<T> vec, int window, Lambda&& func, T init){
int final_size = vec.size() - window 1;
vector<T> result(final_size);
for (int k = 0; k < final_size; k )
result[k] = accumulate(vec.begin() k, vec.begin() k window, init, func);
return result;
};
int main()
{ vector<double> myvec{1,2,2.3,3,4,5,6,7,8,9,1,2,3,4,5,6,7};
//rolling sum
vector<double> v = roll_fun<double>(myvec, 5,plus<double>(), 0.0);
for(auto i: v) cout<<i<<' ';
cout<<endl;
// rolling mean
vector<double> v1 = roll_fun<double>(myvec, 5,[](double x, double y){return x y/5;}, 0);
for(auto i: v1) cout<<i<<' ';
cout<<endl;
//rolling max
vector<double> v2 = roll_fun<double>(myvec, 5,[](double x, double y){return x>y?x:y;}, 0.0);
for(auto i: v2) cout<<i<<' ';
cout<<endl;
return 0;
}
CodePudding user response:
The whole aux
and sumAux
handling is making your logic more complicated than it needs to be.
Try something more like this:
#include <algorithm>
const size_t size = numVec.size();
const size_t increment = 5;
for (size_t a = 0; a < size; a)
{
size_t stop = a std::min(size-a, increment);
sum = 0;
for (size_t b = a; b < stop; b)
sum = numVec[b].num;
cout << "Sum: " << sum << endl;
}
Alternatively:
#include <algorithm>
#include <numeric>
auto end = numVec.end();
decltype(numVec)::difference_type increment = 5;
for (auto start = numVec.begin(); start != end; start)
{
auto stop = start std::min(end-start, increment);
sum = std::accumulate(start, stop, 0,
[](auto a, const auto &elem){ return a elem.num; }
);
cout << "Sum: " << sum << endl;
}