[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Reading items from a text file to a vector

zr

11/14/2008 1:01:00 AM

Hi,

i need to read a text file which contains a list of items, all of type
ItemType, separated by whitespace and newlines. For each line, there
will be a vector<ItemType> object that will store the integers read in
that line. There will be a single vector<vector<ItemType>> object that
will stores all of the vector<ItemType> objects mentioned in the
previous sentence.
I wrote a quick implementation and it seems to be working, but i would
like to hear some opinions on what may be incorrect or may be
improved, especially exception and runtime error handling. Assume that
the required operator>> in code line 13 is defined.

TIA

1 template <class ItemType>
2 void collect(istream& source, vector<vector<ItemType>>& db) {
3 while (source.good()) {
4 string s;
5 getline(source, s, '\n');
6 istringstream iss(s);
7 if (iss.bad() || 0==s.size())
8 break;
9 vector<ItemType> t;
10
11 while (iss.good()) {
12 ItemType item;
13 iss >> item;
14 t.push_back(item);
15 }
16 db.push_back(t);
17 }
18}

4 Answers

red floyd

11/14/2008 2:44:00 AM

0

zr wrote:
> Hi,
>
> i need to read a text file which contains a list of items, all of type
> ItemType, separated by whitespace and newlines. For each line, there
> will be a vector<ItemType> object that will store the integers read in
> that line. There will be a single vector<vector<ItemType>> object that
> will stores all of the vector<ItemType> objects mentioned in the
> previous sentence.
> I wrote a quick implementation and it seems to be working, but i would
> like to hear some opinions on what may be incorrect or may be
> improved, especially exception and runtime error handling. Assume that
> the required operator>> in code line 13 is defined.
>
Don't use line numbers in your posts. It makes it difficult for
readers to cut&paste your code.
Correction on your line2 and on your lines 11-15.


>
> 1 template <class ItemType>
> 2 void collect(istream& source, vector<vector<ItemType>>& db) {
vector<vector<ItemType> >& db

> 3 while (source.good()) {
> 4 string s;
> 5 getline(source, s, '\n');
> 6 istringstream iss(s);
> 7 if (iss.bad() || 0==s.size())
> 8 break;
> 9 vector<ItemType> t;
> 10

> 11 while (iss.good()) {
> 12 ItemType item;
> 13 iss >> item;
> 14 t.push_back(item);
> 15 }
for (ItemType item; iss >> item; )
t.push_back(item);


> 16 db.push_back(t);
> 17 }
> 18}
>

red floyd

11/14/2008 6:20:00 AM

0

red floyd wrote:
> zr wrote:
>> Hi,
>>
>> i need to read a text file which contains a list of items, all of type
>> ItemType, separated by whitespace and newlines. For each line, there
>> will be a vector<ItemType> object that will store the integers read in
>> that line. There will be a single vector<vector<ItemType>> object that
>> will stores all of the vector<ItemType> objects mentioned in the
>> previous sentence.
>> I wrote a quick implementation and it seems to be working, but i would
>> like to hear some opinions on what may be incorrect or may be
>> improved, especially exception and runtime error handling. Assume that
>> the required operator>> in code line 13 is defined.
>>
> Don't use line numbers in your posts. It makes it difficult for
> readers to cut&paste your code.
> Correction on your line2 and on your lines 11-15.

Forgot the correction on 3-5.
>
>
>>
>> 1 template <class ItemType>
>> 2 void collect(istream& source, vector<vector<ItemType>>& db) {
> vector<vector<ItemType> >& db
>
>> 3 while (source.good()) {
>> 4 string s;
>> 5 getline(source, s, '\n');
for (string s; getline(source, s); ) // '\n' is implied
>> 6 istringstream iss(s);
>> 7 if (iss.bad() || 0==s.size())
>> 8 break;
>> 9 vector<ItemType> t;
>> 10
>
>> 11 while (iss.good()) {
>> 12 ItemType item;
>> 13 iss >> item;
>> 14 t.push_back(item);
>> 15 }
> for (ItemType item; iss >> item; )
> t.push_back(item);
>
>
>> 16 db.push_back(t);
>> 17 }
>> 18}
>>

James Kanze

11/14/2008 10:21:00 AM

0

On Nov 14, 2:00 am, zr <zvir...@gmail.com> wrote:
> i need to read a text file which contains a list of items, all
> of type ItemType, separated by whitespace and newlines. For
> each line, there will be a vector<ItemType> object that will
> store the integers read in that line. There will be a single
> vector<vector<ItemType>> object that will stores all of the
> vector<ItemType> objects mentioned in the previous sentence.

> I wrote a quick implementation and it seems to be working, but
> i would like to hear some opinions on what may be incorrect or
> may be improved, especially exception and runtime error
> handling. Assume that the required operator>> in code line 13
> is defined.

As you've posted it, it won't compile:-). But in fact, it isn't
guaranteed to work, even with the correction to the syntax.

> 1 template <class ItemType>
> 2 void collect(istream& source, vector<vector<ItemType>>& db) {

">>" is a shift left operator, and doesn't close two open template
lists; you need "> >" (unless your compiler has already
implemented this feature of the next version of the standard).

> 3 while (source.good()) {

And this is an error; source.good() does NOT mean that the next
input is guaranteed to succeed. (In practice, what will
probably happen is that you'll get an extra, empty list at the
end of your results.)

> 4 string s;
> 5 getline(source, s, '\n');
> 6 istringstream iss(s);
> 7 if (iss.bad() || 0==s.size())
> 8 break;
> 9 vector<ItemType> t;
> 10
> 11 while (iss.good()) {

Same thing here. Most of the time, this will work anyway, but
if you have a line which contains trailing white space, it may
result in an additional default constructed item at the end of
the list.

> 12 ItemType item;
> 13 iss >> item;
> 14 t.push_back(item);
> 15 }
> 16 db.push_back(t);
> 17 }
> 18}

In general, you should always test *after* reading from a
stream, to know if the input succeeded or failed. And be wary
of the names of the status functions in the streams; they are
very misleading. (I've never found a use for good(), for
example.) Taking this into account, your code should probably
look something like:

std::string s ;
while ( std::getline( source, s ) ) {
std::istringstream iss( s ) ;
std::vector< ItemType >
t ;
ItemType item ;
while ( iss >> item ) {
t.push_back( item ) ;
}
db.push_back( t ) ;
}

In addition, you might want to think about other possible input
errors: what happens if an item in the file is misformatted.
(You can typically detect this by checking iss.eof() after the
inner loop above; if input failed and you don't have eof() or
bad(), then you have a formatting error.)

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Kai-Uwe Bux

11/15/2008 9:22:00 AM

0

zr wrote:

> Hi,
>
> i need to read a text file which contains a list of items, all of type
> ItemType, separated by whitespace and newlines. For each line, there
> will be a vector<ItemType> object that will store the integers read in
> that line. There will be a single vector<vector<ItemType>> object that
> will stores all of the vector<ItemType> objects mentioned in the
> previous sentence.
> I wrote a quick implementation and it seems to be working, but i would
> like to hear some opinions on what may be incorrect or may be
> improved, especially exception and runtime error handling. Assume that
> the required operator>> in code line 13 is defined.
>
> TIA
>
> 1 template <class ItemType>
> 2 void collect(istream& source, vector<vector<ItemType>>& db) {
> 3 while (source.good()) {
> 4 string s;
> 5 getline(source, s, '\n');
> 6 istringstream iss(s);
> 7 if (iss.bad() || 0==s.size())
> 8 break;
> 9 vector<ItemType> t;
> 10
> 11 while (iss.good()) {
> 12 ItemType item;
> 13 iss >> item;
> 14 t.push_back(item);
> 15 }
> 16 db.push_back(t);
> 17 }
> 18}

You have received some suggestions so far. The following is radically
different: (a) globally and (b) locally.

(a) The two problems of converting a single line and converting a whole file
are intermingled in your solution. I suggest taking those issues apart.
Also, you deal with vectors of vectors specifically. I think, one can be
more general.

(b) Just for fun, I used iterators and standard algorithms. Two different
methods of error reporting are employed: exceptions if there is no stream
to return or the status bits of the stream if present.

Here goes:

#include <iostream>
#include <istream>
#include <string>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
#include <stdexcept>

struct line : public std::string {};

std::istream & operator>> ( std::istream & istr, line & l ) {
return ( std::getline( istr, l ) );
}

template < typename Sequence >
Sequence scan_line ( std::string const & l ) {
std::istringstream istr ( l );
Sequence result;
typedef typename Sequence::value_type value_type;
std::copy( std::istream_iterator< value_type >( istr ),
std::istream_iterator< value_type >(),
std::back_inserter( result ) );
if ( ! istr.eof() || istr.bad() ) {
throw ( std::invalid_argument( "line invalid\n" ) );
}
return ( result );
}

template < typename Sequence >
std::istream & collect ( std::istream & istr, Sequence & seq ) {
typedef typename Sequence::value_type value_type;
std::transform( std::istream_iterator< line >( istr ),
std::istream_iterator< line >(),
std::back_inserter( seq ),
& scan_line< value_type > );
return ( istr );
}

int main ( void ) {
std::vector< std::vector<int> > ivv;
try {
collect( std::cin, ivv );
if ( std::cin.eof() && ! std::cin.bad() ) {
for ( unsigned long n = 0; n < ivv.size(); ++n ) {
for ( unsigned long m = 0; m < ivv[n].size(); ++m ) {
std::cout << ivv[n][m] << " ";
}
std::cout << "\n";
}
} else {
std::cerr << "File format error\n";
}
}
catch ( std::invalid_argument const & i ) {
std::cerr << i.what();
}
}


BTW: I do not claim that this is "better". I just think you should know that
there are many ways to go about this.


Best

Kai-Uwe Bux