Print elements of vector

M

Markus Dehmann

I am wondering what is the "best" code to print out the elements of a
vector.
Assume they contain strings.

With "best", I mean shortest and most readable at the same time.

Of course, a for loop can be done. But I guess one can do it more
elegantly.
Something like this would be possible:

copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n"));

But I don't like it: The line begins with "copy", and that's
confusing. It has a kind of misleading semantics.

Then better with for_each. How would that look like? Or is there a
better version?

I wonder why there is no to_string(const string& delimiter) function
in vector. Then, we could write:

cout << v.to_string("\n") << endl;

Markus
 
M

Matthew Del Buono

Markus Dehmann said:
I am wondering what is the "best" code to print out the elements of a
vector.
Assume they contain strings.

With "best", I mean shortest and most readable at the same time.

Of course, a for loop can be done. But I guess one can do it more
elegantly.
Something like this would be possible:

copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n"));

But I don't like it: The line begins with "copy", and that's
confusing. It has a kind of misleading semantics.

Then better with for_each. How would that look like? Or is there a
better version?

I wonder why there is no to_string(const string& delimiter) function
in vector. Then, we could write:

cout << v.to_string("\n") << endl;

Markus

IMHO, use arrays directly. With direct access like that, you don't have to
worry about something like this. It would undoubtably be faster -- think
about it. On the inside, a vector is just an easy interface for a linked
list.

-- Matt
 
J

John Harrison

IMHO, use arrays directly. With direct access like that, you don't have
to
worry about something like this. It would undoubtably be faster -- think
about it. On the inside, a vector is just an easy interface for a linked
list.

A vector is an easy interface to an array. It has no similarly to a linked
list. And don't knock easy interfaces.

And both of the OP suggestions std::copy and std::for_each are applicable
to arrays as well, so maybe you do have something to worry about.

john
 
A

Ali Cehreli

Something like this would be possible:

copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n"));

But I don't like it: The line begins with "copy", and that's confusing.
It has a kind of misleading semantics.

Here is a to_string that puts the delimiter between the objects, not
after the last one:

#include <sstream>
#include <string>

using namespace std;

template <class Collection>
string to_string(Collection const & collection,
char const * delimiter)
{
typedef typename Collection::const_iterator Iter;

Iter beg = collection.begin();
Iter const end = collection.end();

if (beg == end)
{
return string();
}

std::eek:stringstream os;

os << *beg;
++beg;

for ( ; beg != end; ++beg)
{
os << delimiter << *beg;
}

return os.str();
}

template<class Collection>
string to_string(Collection const & collection,
string const & delimiter)
{
return to_string(collection, delimiter.c_str());
}

#include <vector>
#include <list>
#include <iostream>

template <class Type, size_t N>
size_t arraySize(Type const (&)[N])
{
return N;
}

void string_test()
{
string const array[] = { "Hello", "cool", "world" };
vector<string> words(array, array + arraySize(array));
cout << to_string(words, string(" ")) << "!\n";
}

void int_test()
{
int const array[] = { 1, 7, 42, 100 };
vector<int> numbers(array, array + arraySize(array));
cout << to_string(numbers, " + ") << '\n';
}

void empty_test()
{
list<double> doubles;
cout << "Empty: " << to_string(doubles, " - ") << '\n';
}

int main()
{
string_test();
int_test();
empty_test();
}

Ali
 
J

Jeff

I am wondering what is the "best" code to print out the elements of a
vector.
Assume they contain strings.

With "best", I mean shortest and most readable at the same time.

Of course, a for loop can be done. But I guess one can do it more
elegantly.
Something like this would be possible:

copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n"));

This is as good as it gets. There ain't nothin better.
But I don't like it: The line begins with "copy", and that's
confusing. It has a kind of misleading semantics.

Then better with for_each. How would that look like? Or is there a
better version?

I wonder why there is no to_string(const string& delimiter) function
in vector. Then, we could write:

cout << v.to_string("\n") << endl;

This method would be intrinsically less efficient. It would be
dynamically filling and resizing a string, then pumping it to cout in
one shot. A slow down would be noticeable if the vector were very
large.

Whereas even with a very large array, the copy() approach would be
efficient with less memory overhead.
 
D

David Hilsee

Markus Dehmann said:
I am wondering what is the "best" code to print out the elements of a
vector.
Assume they contain strings.

With "best", I mean shortest and most readable at the same time.

Of course, a for loop can be done. But I guess one can do it more
elegantly.
Something like this would be possible:

copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n"));

But I don't like it: The line begins with "copy", and that's
confusing. It has a kind of misleading semantics.

In the end, the for loop is probably the most readable, and it's only
slightly more verbose. But beauty is in the eye of the beholder, so I'm
sure others find the ostream_iterator version readable. If you want a
one-line method for displaying the contents of a container that avoids
"misleading semantics", then you could write a trivial function.

template <class T>
void display_container( const T& v ) {
// display elements using method of choice
std::copy(v.begin(), v.end(), std::eek:stream_iterator<typename
T::value_type>(std::cout, "\n"));
}

int main() {
std::vector<int> v;
// ...
display_container(v);
}
 
S

Siemel Naran

Jeff said:
(e-mail address removed) (Markus Dehmann) wrote in message

This method would be intrinsically less efficient. It would be
dynamically filling and resizing a string, then pumping it to cout in
one shot. A slow down would be noticeable if the vector were very
large.

Whereas even with a very large array, the copy() approach would be
efficient with less memory overhead.

Not necessarily. If v.to_string(v) or to_string(v) returns a proxy object,
then we can overload ostream's operator<< to print the vector elements to
the stream directly. The proxy object would store a pointer to the vector
along with the delimeter character. It's syntactic sugar for the same old
loop or std::copy thing.
 
M

Marc

Markus said:
copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n"));

Then better with for_each. How would that look like?

That is an interesting question. I don't know any way to do this without
writing your own class:

struct print {
ostream& out;
print(ostream& os): out(os) {}
template <typename T>
void operator()(T const& x){ out << x; }
};

(I removed the delimiter to simplify the example)

It should have been possible to create the object print(cout) using only
the functional capabilities of c++, but bind1st accepts only const
arguments so it cannot be used to bind cout as the first argument of <<
or ostream_iterator<string>(cout) as the first argument of =.

bind1st(mem_fun_ref<ostream&,ostream,T>(&ostream::eek:perator<<),cout)
would be nice if it worked, wouldn't it? (no working around the fact
that you have to explicit the template arguments for an overloaded
function, it seems)

Or (where typ stands for ostream_iterator<T>):
bind1st(mem_fun_ref<typ&,typ,const T&>(&typ::eek:perator=),typ(cout))

I hope some day something similar will be possible... (bind1st is not
the only thing that prevents the second exemple from working as is, also
bind1st_ref and allowing reference to reference would be enough for the
first one)
 
J

Jeff Flinn

Markus,

Markus Dehmann said:
I am wondering what is the "best" code to print out the elements of a
vector.
Assume they contain strings.

With "best", I mean shortest and most readable at the same time.

Of course, a for loop can be done. But I guess one can do it more
elegantly.
Something like this would be possible:

copy(v.begin(), v.end(), ostream_iterator<string>(cout, "\n"));

But I don't like it: The line begins with "copy", and that's
confusing. It has a kind of misleading semantics.

Agreed, and forces one to play games if a different terminating delimiter is
desired.
Then better with for_each. How would that look like? Or is there a
better version?

I wonder why there is no to_string(const string& delimiter) function
in vector. Then, we could write:

cout << v.to_string("\n") << endl;

How about something like:

std::cout << range_stream( v.begin(), v.end(), "{ ", ", " " }\n" );


With the following definition of range_stream:

#if !defined(RangeStreamerHeaderIncluded)
#define RangeStreamerHeaderIncluded

template< class tItr, class tDBeg, class tDInner, class tDEnd > class
range_streamer
{
tItr mBeg;
tItr mEnd;
tDBeg mDBeg;
tDInner mDInner;
tDEnd mDEnd;
public:
range_streamer( tItr aBeg, tItr aEnd, tDBeg aDBeg, tDInner aDInner, tDEnd
aDEnd )
: mBeg ( aBeg )
, mEnd ( aEnd )
, mDBeg ( aDBeg )
, mDInner( aDInner )
, mDEnd ( aDEnd )
{}

template< class tStream >
void OutputTo( tStream& s )const
{
if( mBeg != mEnd )
{
tItr lItr = mBeg;

s << mDBeg << *lItr;

for( ++lItr ; lItr != mEnd ; ++lItr )
{
s << mDInner << *lItr;
}
s << mDEnd;
}
}
};

template< class tItr, class tDBeg, class tDInner, class tDEnd >
inline range_streamer<tItr,tDBeg,tDInner,tDEnd>
range_stream( tItr aBeg, tItr aEnd, tDBeg aDBeg, tDInner aDInner, tDEnd
aDEnd )
{
return range_streamer<tItr,tDBeg,tDInner,tDEnd>( aBeg, aEnd, aDBeg,
aDInner, aDEnd );
}

template< class tStream, class tItr, class tDBeg, class tDInner, class tDEndinline tStream& operator<<( tStream& s, const
range_streamer<tItr,tDBeg,tDInner,tDEnd>& aRS )
{
aRS.OutputTo(s);

return s;
}

#endif //RangeStreamerHeaderIncluded
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,172
Messages
2,570,934
Members
47,477
Latest member
ColumbusMa

Latest Threads

Top