Selecting a Vector row for average

I'm trying to create a two-dimensional array that contains 25 random generated numbers and calculates the average and total of 5 integers in each row.

I was able to display the vector with random integers that has an average for the entire thing and an output that shows 5 completely new integers in a row with their total and average.

The problem is I need to grab each row from the vector to display the same 5 numbers from the vector above to calculate the average and total for each individual row showing 5 numbers.

Here is what I have, I'm a newbie to C++ so I'm really struggling to figure this out, any help is appreciated!
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124


#include "stdafx.h"
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <vector>
#include <random>
#include <numeric>


using namespace std; // Just to make the code easier  to read in the example...

					 // Template function to return the average of the elements in a vector
template <class T> T average(const vector<T>& vec)
{
	static_assert(std::is_arithmetic<T>::value,
		"Type parameter for average() must be arithmetic.");
	T sum{};
	for_each(cbegin(vec), cend(vec),
		[&sum](const T& value) { sum += value; });
	return sum / vec.size();
}

template <class T> T addition(const vector<T>& vec)
{
	static_assert(std::is_arithmetic<T>::value,
		"Type parameter for add() must be arithmetic.");
	T sum{};
	for_each(cbegin(vec), cend(vec),
		[&sum](const T& value) {sum += value; });
	return sum; 
}


template <class T> void setValues(vector<T>& vec, T start, T increment)		// Template function to set a vector to values beginning with start
{																			// and incremented by increment
	static_assert(std::is_arithmetic<T>::value,
		"Type parameter for setValues() must be arithmetic.");
	T current{ start };
	generate(begin(vec), end(vec),
		[increment, &current]() { T result{ current };
	current += increment;
	return result; });
}

template<class T> void randomValues(vector<T>& vec, T min_value, T max_value) // Template function to set a vector to random values between min and max
{
	static_assert(std::is_arithmetic<T>::value,
		"Type parameter for randomValues() must be arithmetic.");

	random_device engine;                // Random number source
	auto max_rand = engine.max();        // Maximum random value
	auto min_rand = engine.min();        // Minimum random value

	generate(begin(vec), end(vec),
		[&engine, max_rand, min_rand, min_value, max_value]
	{  return static_cast<T>(static_cast<double>(engine()) /
		max_rand*(max_value - min_value) + min_value); });
}

template<class T> void listVector(const vector<T>& vec) // Template function to list the values in a vector
{
	int count{};       // Used to control outputs per line
	const int valuesPerLine{ 5 };
	for_each(cbegin(vec), cend(vec),
		[&count, valuesPerLine](const T& n) {
		cout << setw(5) << n << "  ";
		if (++count % valuesPerLine == 0)
			cout << endl; });
}


int main()
{
	vector<int> integerData(25);
	randomValues(integerData, 1, 100);            // Set random integer values
	cout << "25 random generated numbers: " << endl;
	listVector(integerData);
	cout << "\nAverage value is " << average(integerData) << endl;

	{
		vector<int> integerData(5);
		randomValues(integerData, 1, 100);
		cout << "\nRow 1 " << setw(5) << endl;
		listVector(integerData);
		cout << "\nAverage =  " << average(integerData) << endl;
		cout << "Total =  " << addition(integerData) << endl;
	}
	{
		vector<int> randomData(5);
		randomValues(randomData, 1, 100);
		cout << "\nRow 2 " << setw(5) << endl;
		listVector(randomData);
		cout << "\nAverage =  " << average(randomData) << endl;
		cout << "Total =  " << addition(randomData) << endl;
	}
	{
		vector<int> randomData(5);
		randomValues(randomData, 1, 100);
		cout << "\nRow 3 " << setw(5) << endl;
		listVector(randomData);
		cout << "\nAverage =  " << average(randomData) << endl;
		cout << "Total =  " << addition(randomData) << endl;
	}
	{
		vector<int> randomData(5);
		randomValues(randomData, 1, 100);
		cout << "\nRow 4 " << setw(5) << endl;
		listVector(randomData);
		cout << "\nAverage =  " << average(randomData) << endl;
		cout << "Total =  " << addition(randomData) << endl;
	}
	{
		vector<int> randomData(5);
		randomValues(randomData, 1, 100);
		cout << "\nRow 5 " << setw(5) << endl;
		listVector(randomData);
		cout << "\nAverage =  " << average(randomData) << endl;
		cout << "Total =  " << addition(randomData) << endl;
	}

	
}
Last edited on
You want to store logical 2D matrix in 1D array. Good.

You need to convert between 1D and 2D indices. Both directions are possible:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <iomanip>

int main()
{
    constexpr int COLS {5};

    for ( int count=0; count<25; ++count ) {
        std::cout << " [" << count / COLS << "][" << count % COLS << ']';
        if ( 0 == (count + 1) % COLS ) std::cout << '\n';
    }
    std::cout << '\n';

    for ( int row=0; row<5; ++row ) {
        for ( int col=0; col<COLS; ++col ) {
            std::cout << std::setw(4) << row * COLS + col;
        }
        std::cout << '\n';
    }
}
> I'm a newbie to C++ so I'm really struggling to figure this out

It's quite a good effort for someone just starting out with C++. Well done!



> The problem is I need to grab each row from the vector to display the same 5 numbers
> from the vector above to calculate the average and total for each individual row.

A canonical way to do this would be to create a view of each row,
which can then be treated on its own as a sequence of values.


For instance, something along these lines (here the row_view is a read-only view):

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <vector>
#include <random>
#include <type_traits>
#include <numeric>

// generate a vector of size n x n filled with random values in the range [minv,maxv]
template < typename T > std::vector<T> generate_random_vector( std::size_t n, T minv, T maxv )
{
    static_assert( std::is_arithmetic<T>::value, "Type must be arithmetic." );

    // entropy is precious; we use a random device to generate a seed for the prng
    // and then use the prng for generating the random values for the vector
    static std::mt19937 rng( std::random_device{}() ) ;
    using distribution = typename std::conditional< std::is_integral<T>::value,
                                                    std::uniform_int_distribution<T>,
                                                    std::uniform_real_distribution<T> >::type ;

    distribution distrib( minv, maxv ) ;
    std::vector<T> vec(n*n) ;
    // http://www.stroustrup.com/C++11FAQ.html#for
    for( T& v : vec ) v = distrib(rng) ;
    return vec ;
}

// a read-only view of a row in a flattened out 2D array a la std::string_view in C++17
// (in C++17, we could just use std::basic_string_view<T>)
template < typename T >  struct row_view
{
    using value_type = T ;

    const T* const begin_ ;
    const T* const end_ ;

    const T* begin() const { return begin_ ; }
    const T* end() const { return end_ ; }
    std::size_t size() const { return end() - begin() ; }
};

// return a view of row #row_num where each row consists of ncols values
template < typename T > row_view<T> row( const std::vector<T>& vec, std::size_t ncols, std::size_t row_num )
{
    // validation elided bor brevity
    const auto begin = std::addressof( vec.front() ) + row_num*ncols ;
    return row_view<T>{ begin, begin+ncols } ;
}

template < typename RANGE > long double average( const RANGE& r ) // return NaN if sequence is empty
{
    // http://en.cppreference.com/w/cpp/algorithm/accumulate
    return std::accumulate( r.begin(), r.end(), 0.0L ) / r.size() ;
    // return std::accumulate( std::begin(r), std::end(r), 0.0L ) / std::size(r) ; // C++17
}

template < typename SEQ > std::ostream& print_seq( const SEQ& seq, std::ostream& stm = std::cout )
{
    for( const auto& v : seq ) stm << v << ' ' ;
    return stm ;
}

template < typename T > std::ostream& print_mtx( const std::vector<T>& vec, std::size_t ncols, std::ostream& stm = std::cout )
{
    for( std::size_t nr = 0 ; nr < vec.size()/ncols ; ++nr )
        print_seq( row( vec, ncols, nr ), stm ) << stm.widen('\n') ;

    return stm ;
}

template < typename T > void test( std::size_t n, T minv, T maxv )
{
    const auto vec = generate_random_vector<T>( n, minv, maxv );

    print_mtx( vec, n ) ;
    std::cout << "\nmtx average: " << average(vec) << "\n\nrows:\n" ;

    for( std::size_t r = 0 ; r < n ; ++r )
    {
        const auto rview = row( vec, n, r ) ;
        print_seq(rview) << "  (avg: " << average(rview) << ")\n" ;
    }

    std::cout << "\n---------------------\n\n" ;
}

int main()
{
    std::cout << std::fixed ;

    test<int>( 9, 100, 999 ) ;
    test<double>( 6, 15.0, 58.0 ) ;
}

http://coliru.stacked-crooked.com/a/3389411d9be0d323
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
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <valarray>
using namespace std;


template<typename T> void run( int rows, int cols, T vmin, T vmax, int w, int p )
{
   // Generate a 1-d array of random numbers
   valarray<T> A( rows * cols );
   for ( T &e : A ) e = vmin + ( vmax - vmin ) * (double)rand() / RAND_MAX;

   cout << fixed << setprecision( p );

   // Loop through rows
   for ( int r = 0, start = 0; r < rows; r++, start += cols )
   {
      valarray<T> ROW = A[slice(start,cols,1)];                 // Grab row r
      double average = (double)ROW.sum() / cols;                // Calculate average

      for ( T e : ROW ) cout << setw( w )  << e << ' ';         // Output row
      cout << "    --->    " << setw( w ) << average << '\n';   // Output average
   }
}


int main()
{
   srand( time( 0 ) );

   run( 3, 5,    0, 100, 6, 3 );          cout << "\n\n";
   run( 5, 3, -1.0, 1.0, 8, 3 );
}

     2     45     92     15     42     --->    39.200
    55     30     13     34     33     --->    33.000
    97     26     10     87      3     --->    44.600


   0.186    0.872    0.701     --->       0.586
   0.742   -0.539   -0.507     --->      -0.101
  -0.318    0.687    0.679     --->       0.350
  -0.494    0.150   -0.749     --->      -0.364
   0.619    0.187    0.422     --->       0.409

Last edited on
I really appreciate everyone's help!!. I attempted to utilize each example but I ran into a lot of problems. I ended up using JLBorges's example to get the result I needed and it worked great!! I really appreciate the link for more information regarding some of the functions.

As I haven't learned about several of the functions you used, is the std::ostream& print_mtx necessary for output? What is the difference between using stream and cout << "" <<endl; for example? (sorry if I'm not using the correct terms)
> is the std::ostream& print_mtx necessary for output?
> What is the difference between using stream and cout << "" <<endl; for example?

If we would always want to send the output to standard output (stdout), we can hard-code std::cout

For example, this would print "hello" on stdout void say_hello() { std::cout << "hello" ; }


This is somewhat more flexible: it would print "hello" on any output stream. If no stream is specified, the default is stdout, but we have the option of sending the output to a file by providing an output filestream as the argument.
void say_hello2( std::ostream& stm = std::cout ) { stm << "hello" ; }


This version, which returns a reference to the stream is a small, but often important, refinement.

std::ostream& say_hello3( std::ostream& stm = std::cout ) { return stm << "hello" ; }

This helps us in two ways.
One, we can chain calls: for example, print "hello" and then a new line on stdout say_hello3() << '\n' ;
Two, it provides a convenient (and canonical) way to check for success or failure of the i/o operation:
For example: if( say_hello3( myfile ) ) { /* success: output was written to myfile */ }
I attempted to utilize each example but I ran into a lot of problems. I ended up using JLBorges's example to get the result I needed

Problems are good, because if you manage to figure them out, you learn in the process. Can you describe some of the unsolved ones, for educational purposes?

Philosophical question: is it the numbers that a program spits out numbers or the understanding of how to spit out numbers that you actually need?



std::cout and std::cin are both stream objects. They are streams. Difference between using one stream or an another is thus in who decides which stream to use? The function, or the caller(s) of the function.
Topic archived. No new replies allowed.