Printing Vectors

Hi Gods of C++,

I am trying to create a generic print vector function that would be called from main function. The function should be flexible enough to print a 1D or 2D vector. Can this be done?

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
//Vectors

#include<iostream>
#include<vector>
#include <fstream>
#include <sstream>

using namespace std;

void Print2DVec(vector<vector<double>>const& v)
{  
   ofstream myfile;
   myfile.open("myexample.txt", ios_base::app);
   for (int i = 0; i < v.size(); i++)
   {
	   for (int j = 0; j< v.size();j++)
	   {
		   
		   myfile<<v[i][j] <<"|";
	   }

	   myfile<<endl;
   }
}

int main()
{

	vector< vector<double> > v(15, vector<double>(15,1.1));

    Print2DVec(v);
	
	cin.get();

    return 0;
}
First: line 16.

The v is a vector that has v.size() elements. Each element is a vector that has how many elements?

The answer is not v.size(). It can actually be different for each element of v.


1D vector is a different type than 2D vector, unless they share interface. If they share interface, they probably can print themselves too -- each with its own function.


You say "generic", but your function is hardcoded to append to specific file. A more generic function would take an ostream as parameter and let the caller decide what stream to write to.

Continuing on generic, my vectors don't have doubles ... (std::vector is less "a type" and more a template for a family of types that are used similarly)

And then some: Do we even agree on the field delimiter? The "CSV" format has a long list to choose from and it is not the only tabular format. Furthermore, the | is a pipe for most shells, i.e. special.


Printing a vector ... see one example: http://www.cplusplus.com/reference/iterator/ostream_iterator/


tldr;
There are many decisions on the route to good design and many different good designs.
Thank you so much for the reply however when I am trying to do as you had suggested I am getting an error..pardon my lack of understanding of vectors :(

------------------------------------New Code------------------------------------------

#include <fstream>
#include <sstream>

using namespace std;

int main ()
{

//Output File
ofstream myfile;
myfile.open("myexample.txt", ios_base::app);

//Create 1-D Vector:
vector<int> myvector1(5,0);

for (int i=1; i<5; ++i)
{
myvector1.push_back(i*5);
}

//Create 2-D Vector:
vector<vector<int> > myvector2 ( 5, vector<int> ( 5 ) );

int k = 0;
for ( int i = 0; i < 5; i++ )
{
for ( int j = 0; j < 5; j++ )
{
myvector2[i][j] = k++;
}
}

//iterator for both 1D and 2D vectors:
ostream_iterator<int> out_it (myfile,",");

copy ( myvector1.begin(), myvector1.end(), out_it );

copy ( myvector1.begin(), myvector2.end(), out_it ); //ERROR???

cin.get();

return 0;
}
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
#include <iostream>
#include <type_traits>
#include <iterator>

namespace detail
{
    template < typename T > struct is_sequence
    {
        template < typename U >
        static char test( U&&, decltype( std::begin( std::declval<U>() ) )* = 0 ) ;

        using two_chars = char[2] ; static two_chars& test(...) ;

        static constexpr bool value = sizeof( test( std::declval<T>() ) ) == 1 ;
    };

    template < typename T > inline
    typename std::enable_if< !is_sequence<T>::value >::type do_print( const T& v, std::ostream& stm )
    { stm << v << ' ' ; }

    template < typename T > inline
    typename std::enable_if< is_sequence<T>::value >::type do_print( const T& seq, std::ostream& stm )
    { stm << "[ " ; for( const auto& v : seq ) do_print(v,stm) ; stm << "] " ;  }

    template < typename F, typename S > // print pair
    inline void do_print( const std::pair<F,S>& p, std::ostream& stm )
    { stm << '{' ; do_print(p.first,stm) ; stm << ',' ; do_print(p.second,stm) ; stm << "} " ; }
}

template < typename... ARGS, template < typename... > class SEQ  > // print standard containers
void print( const SEQ<ARGS...>& seq, std::ostream& stm = std::cout, typename SEQ<ARGS...>::iterator* = 0  )
{ stm << "[ " ; for( const auto& v : seq ) detail::do_print(v,stm) ; stm << "]\n" ; }

// overload for C-style array
template < typename T, std::size_t N > void print( T (&seq)[N], std::ostream& stm = std::cout )
{ stm << "[ " ; for( const auto& v : seq ) detail::do_print(v,stm) ; stm << "]\n" ; }

#include <array>
template < typename T, std::size_t N > // overload for std::array<>
void print( const std::array<T,N>& seq, std::ostream& stm = std::cout )
{ stm << "[ " ; for( const auto& v : seq ) detail::do_print(v,stm) ; stm << "]\n" ; }

#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <unordered_map>
#include <fstream>

int main()
{
    std::ofstream file( "myexample.txt" ) ;
    
    { int seq[] { 1,2,3,4 } ; print(seq) ; print(seq,file) ; } // [ 1 2 3 4 ]

    { std::array<int,4> seq{ { 1,2,3,4 } } ; print(seq) ; print(seq,file) ; } // [ 1 2 3 4 ]

    { std::vector<int> seq{ 1,2,3,4 } ; print(seq) ; print(seq,file) ; } // [ 1 2 3 4 ]

    { std::vector< std::vector<int> > seq { { 1,2,3,4 }, {5,6}, {7,8,9} } ; print(seq) ; print(seq,file) ; }
    // [ [ 1 2 3 4 ] [ 5 6 ] [ 7 8 9 ] ]

    { std::deque< std::list<int> > seq { { 1,2,3,4 }, {5,6}, {7,8,9} } ; print(seq) ; print(seq,file) ; }
    // [ [ 1 2 3 4 ] [ 5 6 ] [ 7 8 9 ] ]

    {
        std::multimap< std::vector<int>, std::set<char> > seq{ { {1,0}, {'A','B'} },
              { {4,5,6}, {'C','D','E'} }, { {1,0},{'F','G', 'H', 'I', 'J' } }, { {4,5,6}, {'K','L','M'} } }  ;
        print(seq) ; print(seq,file) ;
        // [ {[ 1 0 ] ,[ A B ] } {[ 1 0 ] ,[ F G H I J ] } {[ 4 5 6 ] ,[ C D E ] } {[ 4 5 6 ] ,[ K L M ] }  ]
    }

    { 
        std::unordered_map< int, std::deque<char> > seq{ { 1, {'C','D','E'} }, { 2, {'A','B'} }, { 3, {'!','@','#'} } } ; 
        print(seq) ; print(seq,file) ; 
        // [ {3 ,[ ! @ # ] } {2 ,[ A B ] } {1 ,[ C D E ] } ]
    }
}

http://coliru.stacked-crooked.com/a/d51a4886cb2389f8
Note: requires C++11
newbieme's original code, slightly modified:

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
#include <iostream>
#include <fstream>
#include <vector>

void PrintVec( std::vector< std::vector<double> > const & v, std::ostream& stm ) // overload for 2d
{
   for( std::size_t i = 0; i < v.size() ; ++i )
   {
       for( std::size_t j = 0 ; j < v[i].size() ; ++j ) stm << v[i][j] << ' ' ; // ***v[i].size()
	   stm << "  ,   " ;
   }
   stm << '\n' ;
}

void PrintVec( std::vector<double> const & v, std::ostream& stm ) // overload for 1d
{
   for( std::size_t i = 0; i < v.size() ; ++i ) stm << v[i] << ' ' ;
   stm << '\n' ;
}

int main()
{
    std::ofstream file( "myexample.txt" ) ;

    std::vector<double> one_d{ 0, 1, 2, 3, 4 } ;
    PrintVec( one_d, file ) ;

    std::vector< std::vector<double> > two_d{ { 0, 1, 2 },  { 3, 4 }, { 5 }, { 6, 7, 8, 9 } } ;
    PrintVec( two_d, file ) ;
}

http://coliru.stacked-crooked.com/a/518b5492cad35f98
Thank you so much for your reply JLBorges. This serves the purpose.
However my mind wanders towards the iterators.

Can the above be done using iterators as well. I was successfully able to use iterator to print 1D Vector however for 2D Vector I wasn't able to.

Why is that? Thanks again :)
Do you refer to this?
1
2
3
4
5
vector<vector<int> > myvector2 ( 5, vector<int> ( 5 ) );

ostream_iterator<int> out_it (myfile,",");

copy ( myvector1.begin(), myvector2.end(), out_it ); //ERROR??? 

You have two errors there. The first I presume to be a mere typo; you should have myvector2.begin() there.

The real issue is that the std::copy copies each element from myvector2 into out_it, but the type of those elements is vector<int> -- a 1D vector, while the out_it can only accept int -- a number. If you do use an iterator with correct type, then you have the problem that the iterator should be able to print a 1D vector.


JLBorges wrote the PrintVec for 2D vector. We can have iterators there:
1
2
3
4
5
6
for( std::vector< std::vector<double> >::const_iterator i = v.begin(); i != v.end() ; ++i )
{
  for( std::vector<double>::const_iterator j = i->begin(); j != i->end(); ++j ) stm << *j << ' ' ;
  stm << "  ,   " ;
}
stm << '\n' ;

or
1
2
3
4
5
6
7
ostream_iterator<double> out_it ( stm, " " );
for( std::vector< std::vector<double> >::const_iterator i = v.begin(); i != v.end() ; ++i )
{
  std::copy( i->begin(), i->end(), out_it );
  stm << "  ,   " ;
}
stm << '\n' ;

or
1
2
3
4
5
6
7
ostream_iterator<double> out_it ( stm, " " );
for( std::size_t i = 0; i < v.size() ; ++i )
{
  std::copy( v[i].begin(), v[i].end(), out_it );
  stm << "  ,   " ;
}
stm << '\n' ;

Or perhaps:
1
2
3
4
5
for( std::size_t i = 0; i < v.size() ; ++i )
{
  PrintVec( v[i], stm ); // call the 1D version
}
stm << '\n' ;
Thank you soooo much !! :D

I'll be back with more questions
Topic archived. No new replies allowed.