2

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.

everything goes wrong

If you can help me, I thank you very much.

6
  • 1
    If there are only 20 elements in the list, then anything over 15 will have less than 5 elements to choose from. Commented Dec 21, 2021 at 18:00
  • You always break out of the loop when aux = 5 so why not a loop like: for (int a = 0; a < numVec.size() - 5; a++) { for (int b = 0; b < 5; b++) { sum += numVec[a + b].num;.... Commented Dec 21, 2021 at 18:03
  • @JohnnyMopp hm right. But how to tell it to sum the remaining numbers anyway? The problem is the "aux > 4" I think, but I don't know what to replace it for. Commented Dec 21, 2021 at 18:05
  • But the way that you put the for loop the sum values are not the numbers that I should get. Commented Dec 21, 2021 at 18:09
  • 1
    Hint. Do it in O(N). Sum the first 5. Call that S(1, 5). Then S(2, 6) is S(1, 5) - element 1 + element 6. No need for an inner loop, and dealing with the end of the vector is simpler. Simpler approach = fewer bugs. Commented Dec 21, 2021 at 18:12

4 Answers 4

4

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

Sign up to request clarification or add additional context in comments.

1 Comment

What an explanation... 100% understandable. Thanks so much for the time consumed to build this answer.
3

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

Comments

2

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

Comments

1

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

Online Demo

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

Online Demo

2 Comments

Wow, I was actually doing that more complicated that it is... Thank you so much. I just don't understand the usage of the std::min there
std::min() takes 2 inputs and returns whichever one has a lower value. Since you want to process no more than 5 elements at a time, I'm using std::min() to limit the sum to 5 elements if there are more than 5 elements remaining, otherwise I sum just the remaining elements, eg: std::min(6, 5)=5, std::min(4, 5)=4 Like JohnnyMopp said in comments, "If there are only 20 elements in the list, then anything over 15 will have less than 5 elements to choose from."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.