Counting numbers within a Vector

Hi,

Can someone tell me what I'm doing wrong here?
It's almost like the declared integer variables aren't recognised within the "for_each" routine.
Compiler gives error "[variable x] is not captured" (for *all* the below variables. )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void Averagenums(const vector<Draw> Vec)
{
    int avg1 = 0;
    int count1 = 0;
    int avg2 = 0;
    int count2 = 0;
    int avg3 = 0;
    int count3 = 0;
    int avg4 = 0;
    int count4 = 0;
    int avg5 = 0;
    int count5 = 0;
    int avg6 = 0;
    int count6 = 0;

    for_each(Vec.begin(), Vec.end(), [](const Draw d3)
    {
        avg1 += d3.number1;
        count1++;
        avg2 += d3.number2;
        count2++;
        avg3 += d3.number3;
        count3++;
        avg4 += d3.number4;
        count4++;
        avg5 += d3.number5;
        count5++;
        avg6 += d3.number6;
        count6++;



    });

    avg1 = avg1/count1;
    avg2 = avg2/count2;
    avg3 = avg3/count3;
    avg4 = avg4/count4;
    avg5 = avg5/count5;
    avg6 = avg6/count6;
}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <numeric>

double average1( const std::vector<int>& seq )
{
    // https://en.wikipedia.org/wiki/NaN
    // http://en.cppreference.com/w/c/numeric/math/nan
    if( seq.empty() ) return std::nan("") ; // not a number

    int sum = 0 ;

    // http://www.stroustrup.com/C++11FAQ.html#for
    for( int v : seq ) sum += v ;

    return double(sum) / seq.size() ;
}

double average2( const std::vector<int>& seq )
{
    if( seq.empty() ) return std::nan("") ;

    int sum = 0 ;
    // [&]: capture everything (seq, sum) by reference
    // The [&] is a "capture list" specifying that local names used will be passed by reference.
    // http://www.stroustrup.com/C++11FAQ.html#lambda
    std::for_each( seq.begin(), seq.end(), [&] ( int v ) { sum += v ; } ) ;
    
    return double(sum) / seq.size() ;
}

double average3( const std::vector<int>& seq )
{
    if( seq.empty() ) return std::nan("") ;

    // http://en.cppreference.com/w/cpp/algorithm/accumulate
    const int sum = std::accumulate( seq.begin(), seq.end(), 0 ) ;
    return double(sum) / seq.size() ;
}

double average4( const std::vector<int>& seq )
{
    if( seq.empty() ) return std::nan("") ;

    int sum = 0 ;
    for( std::size_t i = 0 ; i < seq.size() ; ++i ) sum += seq[i] ;
    return double(sum) / seq.size() ;
}

int main()
{
    const std::vector<int> vec { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } ;
    std::cout << average1(vec) << '\n'
              << average2(vec) << '\n'
              << average3(vec) << '\n'
              << average4(vec) << '\n' ;
}

http://coliru.stacked-crooked.com/a/0ed55abe149263b0
And one for our humble iterator:
1
2
3
4
5
6
7
8
9
10
double average5 (const std::vector<int>& seq)
{
    if( seq.empty() ) return std::nan("") ;
    int sum = 0 ;
    for (auto itr = seq.begin(); itr != seq.end(); ++itr)
    {
        sum += *itr;
    }
    return (double)(sum)/seq.size();
}

Thanks for this.
So, there is no way to do all this in one function?
How is it that we need an individual function for each number?
need an individual function for each number


:))

These are not functions for each number, average1 ... average5 refer to 5 different ways of doing the same thing, each illustrating a different aspect of C++ and while we're at it let me chuck in a 6th as well involving function objects:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <vector>
#include <algorithm>

struct Sum
{
    Sum(): sum{0} { }
    void operator()(int n) { sum += n; }
    int sum;
};

int main()
{
    const std::vector<int> vec { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } ;
    Sum s = std::for_each(vec.begin(), vec.end(), Sum());
    std::cout << "Average: " << (double)s.sum/vec.size();
}

Oh, okay.
It would seem that I have much to learn about C++!
I don't fully understand the syntax of each of them.

Just looking at your solutions, I am not sure if you realise that the vector MainVec is actually a vector of type "Draw" which is a class containing all these integer variables (e.g. Number1, number2, number3 etc)

Either that, or I am so hopelessly lost that I don't follow your code! 🙂

Many thanks.
Last edited on
vector MainVec is actually a vector of type "Draw"

Yes, we can see that in your post but what you don't show is how Draw is defined so there is no way to suggest implementation of operator + overload for Draw objects that would then incorporate any one of the 6 ways to sum elements of a vector.
If you need help with operator overloading then take a look at below link and/or show the Draw class: https://www.tutorialspoint.com/cplusplus/cpp_overloading.htm
Yes, my apologies.
I probably should have included the class definition:

This is how it is defined:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Draw
{
public:
    int drawnumber;
    long int drawdate;
    int number1;
    int number2;
    int number3;
    int number4;
    int number5;
    int number6;
    int supp1;
    int supp2;

};


I really need practice in accessing the elements of each class definition within the vector.
I thought that this might be a good way to learn.
I'll read your link on overloading.

As always, I am most grateful for your assistance.


I really need practice in accessing the elements of each class definition object within the vector


This can be done in one of the three following ways:
(a) direct member access - possible for std::vector, std::deque but not for some other containers like std::list - so Vec[i] is the i'th element of the vector, indexation starts from 0 and i should be less than or equal Vec.size() - 1
(b) range loops (C++11):
1
2
 for (auto& elem : Vec) 
	{//do stuff with elem which is an actual element of Vec defined over the entire container} 

(c) iterator based access -
1
2
3
4
5
6
7
8
	for (std::vector<Draw>::const_iterator itr = Vec.cbegin(); itr != Vec.cend(); ++itr)
	{ // do stuff with (*itr) i.e the iterator dereferenced is an actual element of Vec}
	//above uses const iterator when you don't want to change the container in any way like printing etc
	//but if you want to sort the vector etc then use normal (non const) iterators
	for (std::vector<Draw>::iterator itr = Vec.begin(); itr != Vec.end(); ++itr)
	//either one of the above statements can also be simplified with auto type deductions (C++11)
	for (auto itr = Vec.begin(); itr != Vec.end(); ++itr)
	{ //now proceed as before } 


As your class attributes are public once you've reached the object you can use the . (dot) operator to access its elements directly. Otherwise, if they were private, you'd have needed separate (public) getter methods

The other issue is how to overload the + operator for class Draw - this can be done as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>

class Draw
{
public:
    int drawnumber;
    long int drawdate;
    int number1;
    int number2;
    int number3;
    int number4;
    int number5;
    int number6;
    int supp1;
    int supp2;

    Draw operator + (const Draw& rhs);

};

int main()
{

}
Draw Draw::operator + (const Draw& rhs)
{
    Draw temp;
    temp.drawnumber = drawnumber + rhs.drawnumber;
    temp.drawdate = drawdate + rhs.drawdate;
    temp.number1 = number1 + rhs.number1;
    temp.number2 = number2 + rhs.number2;
    temp.number3 = number3 + rhs.number3;
    temp.number4 = number4 + rhs.number4;
    temp.number5 = number5 + rhs.number5;
    temp.number6 = number6 + rhs.number6;
    temp.supp1 = supp1 + rhs.supp1;
    temp.supp2 = supp2 + rhs.supp2;

    return temp;//local object, hence return by value (copy) and not reference
}

Now from the various ways to add vector elements that you have been provided you could use any of average1, average2, average4, average5 to add up the elements of the vector
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <iomanip>

struct draw
{
    int number ;
    int date ;

    static constexpr std::size_t N = 6 ;
    int numbers[N] ;

    int supp1 ;
    int supp2 ;
};

void print_averages( const std::vector<draw>& seq )
{
    if( seq.empty() ) return ;

    long long totals[ draw::N ] {} ; // initialise to all zeroes

    for( const auto& a_draw : seq )
    {
        // http://en.cppreference.com/w/cpp/algorithm/transform (3)
        // http://en.cppreference.com/w/cpp/utility/functional/plus
        std::transform( std::begin(a_draw.numbers), std::end(a_draw.numbers),
                        std::begin(totals),
                        std::begin(totals),
                        std::plus<>{} ) ;
    }

    for( std::size_t i = 0 ; i < draw::N ; ++i )
    {
        std::cout << '#' << i+1 << ".  total: " << std::setw(5) << totals[i]
                  << "      average: " << std::fixed << std::setprecision(2)
                  << std::setw(7) << totals[i] / double( seq.size() ) << '\n' ;
    }
}

int main()
{
    const std::vector<draw> all_draws {
                                           { 0, 0, { 11, 12, 13, 14, 15, 16 }, 0, 0 },
                                           { 0, 0, { 12, 22, 33, 13, 17, 27 }, 0, 0 },
                                           { 0, 0, { 13, 32, 53, 11, 19, 38 }, 0, 0 },
                                           { 0, 0, { 14, 42, 73, 10, 21, 49 }, 0, 0 },
                                           { 0, 0, { 15, 52, 93, 11, 23, 60 }, 0, 0 },
                                           { 0, 0, { 16, 62, 73, 12, 25, 71 }, 0, 0 },
                                           { 0, 0, { 17, 72, 53, 13, 27, 82 }, 0, 0 },
                                           { 0, 0, { 18, 82, 33, 14, 29, 93 }, 0, 0 },
                                       };

    print_averages(all_draws) ;
}

http://coliru.stacked-crooked.com/a/1967830f1cfe73da
http://rextester.com/HYPAR33649
Compiler gives error "[variable x] is not captured" (for *all* the below variables. )
Yes, you need to add & to the lambda function:

for_each(Vec.begin(), Vec.end(), [&](const Draw &d3) // Note: [&] (second & is not needed but improves speed)
Many thanks.

I'll see how I go with this.

Thunderchook.
Thanks, Coder777, that is what was missing.

All the other solutions provided were most elegant and clever, but I think, perhaps, are little too advanced for me at this time, as I struggled to understand them and implement them into my larger program.

As I get better at C++ in general, I should return to their code and learn from their wisdom.
I need to do some general study on Operator Overloading and improve my understanding on constructors and destructors.

Again, to all, many thanks! :)
Topic archived. No new replies allowed.