read 2D array from file

Greetings!

What's the current best way to read in a 2D double array from a file?

The structure should be like this, I assume.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void read_dataset(string datafile, vector <vector<double>>& data_arr){
	
	ifstream datasource(datafile);	// open the file			
	string single_char;
	char delim = " ";
	
	while (getline(datasource, single_char, delim)){	
// as far as I understand, 
		// this will read char by char.
		// what's the best way to do it without
		// knowing the no. of elements in a row?
	}
	
return;

}



Regards,
PiF
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
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <fstream>

std::vector<double> parse_line( const std::string& line )
{
    std::istringstream stm(line) ;
    // https://en.cppreference.com/w/cpp/iterator/istream_iterator
    return { std::istream_iterator<double>(stm), std::istream_iterator<double>{} } ;
    // TODO: add error handling
}

std::vector< std::vector<double> > read_dataset( const std::string& datafile )
{
    if( std::ifstream file{datafile} )
    {
        std::vector< std::vector<double> > dataset ;
        std::string line ;
        while( std::getline( file, line ) ) dataset.push_back( parse_line(line) ) ;
        return dataset ;
    }

    else return {} ; // TODO : report file open error
}

int main()
{
    const auto data = read_dataset( "datafile.txt" ) ;
    // ...
}
Thanks JLBorges.

I am not quite sure what the code does.

while( std::getline( file, line ) ) Do I not need to specify the deliminter?
And if this already reads an entire line, what does the function parse_line do?
All these stream objects are confusing...
By default, the delimiter is '\n' (new line).

Yes, it reads a whole line up to the '\n' which is discarded.

parse_line() parses a line into a vector of double - assuming each line contains numbers separated by while-space chars.

std::istringstream operates in a very similar manner to an input file stream - except it works on a string rather the contents of a file.

L10 defines and initialises a std::istringstream type with a value of line.

L12 parses the istringstream stm into the various double elements via extraction and assigns them to the return type std::vector<double>

A vector can be initialised from a pair of iterators stipulating the beginning and one-past-end of the data.

std::istream_iterator<double>(stm) is an iterator pointing to the beginning of the data from the stm stream (ie the beginning of the string line).

std::istream_iterator<double>{} is an iterator to one-past-end.



Thank you, seeplus, for the detailed comments.

Last question to your explanation:
How is std::istream_iterator<double>{} an iterator to one-past-end if I don't even refer the targeted object, stm, anymore?
The default-constructed std::istream_iterator is known as the end-of-stream iterator. When a valid std::istream_iterator reaches the end of the underlying stream, it becomes equal to the end-of-stream iterator.
https://en.cppreference.com/w/cpp/iterator/istream_iterator

Cheers, then I got it!
Topic archived. No new replies allowed.