Read data from file into array VS

Hello everyone,
I am quite new learner of C++. In a data file whose extension is .dat named as Project.dat, there are two arrays that I need to read.They seem like that:
[1, 2, 3]

[[3, 2, 3],
[7, 2, 3],
[9, 2, 3]]
I tried several ways but it did not work. To be sure if the file is open, I have written this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const char* filename = "C:/…/Debug/Project.dat";
	if (argc > 1)
		filename = argv[1];
	ifstream file(filename);
	if (!file) {
		cerr << "ERROR: could not open file '" << filename << "' for reading" << endl;
		cerr << "ERROR: could not open file for reading" << endl;
		cerr << "usage:   " << argv[0] << " <file>" << endl;
		throw(-1);
	}
  if (file.is_open()) {
		std::string line;
		while (std::getline(file, line)) {
			// using printf() in all tests for consistency
			
			printf("%s", line.c_str());
		}
		file.close();
	}


It reads all the data but from beginning to end. However, this is not what I want each value must be read and assingned to a cell of an array X like X[a] or X[a][b]. I do not know how to do it by taking into accoubt the commas and end lines ? I will be evry happy if you can help me. It took quite long time to find a solution for me. Thank you in advance.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
vector<string> linevec;
linevec.reserve(1000); //preallocate some space for efficiency
....
while (std::getline(file, line)) 
  {
      ...
     linevec.push_back(line);
   ...
  }

and now linevec[index] works like an array of lines, you have linevec.size() number of lines, etc. 


end of lines are accounted for: each array element is a line, but the end of line character has been stripped out, so you might print it via
for(i = 0; i < linevec.size(); i++)
cout << linevec[i] << endl; //put end of line back

commas, you said nothing useful about commas. What do you want to do to them?

edit ... misread that, I took 'value' to mean a line because you asked about lines and were reading by lines, but you meant each number.
see below...
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

int main()
{
// ifstream in( "project.dat" );
   istringstream in( "[1, 2, 3]  \n"
                     "           \n"
                     "[[3, 2, 3],\n"
                     " [7, 2, 3],\n"
                     " [9, 2, 3]]\n" );

   const int SIZE = 3;
   double A[SIZE][SIZE];
   double b[SIZE];
   char c;

   if ( in )
   {
      for ( int i = 0; i < SIZE; i++ ) in >> c >> b[i];
      in >> c;

      in >> c;
      for ( int i = 0; i < SIZE; i++ ) 
      {
         for ( int j = 0; j < SIZE; j++ ) in >> c >> A[i][j];
         in >> c >> c;
      }
      in >> c;
   }
   else
   {
      cerr << "File or stream not valid.\n";
      return 1;
   }


   cout << "Rank 1 array is:\n";
   for ( int i = 0; i < SIZE; i++ ) cout << b[i] << '\t';
   cout << "\n\n";

   cout << "Rank 2 array is:\n";
   for ( int i = 0; i < SIZE; i++ ) 
   {
      for ( int j = 0; j < SIZE; j++ ) cout << A[i][j] << '\t';
      cout << '\n';
   }
}


Rank 1 array is:
1	2	3	

Rank 2 array is:
3	2	3	
7	2	3	
9	2	3
Thank you so much Jonnin, It worked well; I have two little quetions: When I modify my code as you said, it reads and prints all the arrays as they are seen in the file (without comma, it is good). I want to assign each different array to a certain defined array name .For example

X=[10 10 10]
Y=[[3 2 3]
[7 2 3]
[9 2 3]]
Because in the Following parts of the code , I will need for example Y[2][2] for a mathematical computation. So I should be able to call an element of the related matrix with a certain name. How can I do that?
Thank you so much lastchance and jonnin. Can't we read the data direcly from .dat file without copying and pasting the arrays in "istringstream" as you did. bacuse I will have many data files to test my models and the values Inside the arrays and their sizes changes from file to file. In the second .dat file for example it migt be Something like that :

X=[2 3]
Y=[[1 2 3
[4 8 12]
That's why , the code must be useable for each file? and them automatically without any manual change (or just with a minor change (manually)).Thank you so much, if we can solve this problem I will be very happy
Can't we read the data direcly from .dat file without copying and pasting the arrays in "istringstream" as you did.
The code is only set up with the "in" stream from a stringstream because that's the only way of demonstrating it in the on-line shell (cpp.sh). If you look at the code carefully you will see that I have commented out the corresponding line to read from a file instead (that isn't possible on-line, obviously). Just comment out whichever one you don't want.

If you want to read arbitrary-sized arrays then YOU have to specify the format of the input file PRECISELY. For example, you used commas in the first example and none in the second; which is it? You also put array names in the second - no idea if they are there. And is there any row/column size information?

Maybe you had better post your assignment; your posts are too ambiguous to give a decent answer.
Thank you so much last chance. You are right , let me clarify everything. In data file I have ararys like this ;

[1, 2, 3]

[[3, 2, 3],
[7, 2, 3],
[9, 2, 3]]

with comma and they do not have any name like X or Y;

In the code, I will assign a name to them so it will be

X=[1 2 3]

Mathematically I dod not need comma.Then Why do they exist? Because , I use the same data set for any other solver and that solver requires to seperate the values by comma.For that solver .dat file is ok. However, to use the same data set for the model I coded in C++ I should use X=[1 2 3] (without comma); You are right; I guesses that I should specify the format like parantheses for 3x3 matrix and commas between the numbers. That's why in my first question, I said I dod not what to do with comma and brackets etc. I did not know how to specify it.

For the size, yes they are known;

Thank you so much
@learner999,
In my code I simply read in a char (variable c) whenever your original example had either a bracket or a comma. I didn't do anything with this char; it was just a separator for the numerical values. You will just have to adapt the reading for whatever format input file you eventually decide to use.


For the size, yes they are known;
Well, it's not clear how. You can either specify them at the start of the input file, or leave the reader to try and work them out. But, either way, you have to make up your mind what the format of the input file is.

if you control the input file, you may want to take note that the more junk you put in there the harder it is to write code to use it. if you write it, then just putting the data in without [] or commas etc would be fine, possibly with a leading dimensions eg 1 3 1 2 3 3 3 ...etc

its possible to rig it so that << just reads the integers out of the file for you, I believe.
give me a min.
Last edited on
Here is code that will read 1D and 2D vectors.
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
#include <iostream>
#include <vector>

using std::vector;
using std::cin;
using std::cout;

std::istream &operator >> (std::istream &in, vector<int> &vec)
{
    char ch;
    int val;
    vec.clear();
    in >> ch;
    if (ch != '[') {
	in.putback(ch);
	in.setstate(std::ios::failbit);
	return in;
    }

    while (in >> val) {
	vec.push_back(val);
	if (!(in >> ch)) {
	    in.putback(ch);
	    in.setstate(std::ios::failbit);
	    return in;
	}
	if (ch == ']') return in; // success
	if (ch != ',') {
	    in.putback(ch);
	    in.setstate(std::ios::failbit);
	    return in;
	}
    }

    // Check for an empty vector
    if (vec.size() == 0) {
	in.clear();
	char ch1;
	if (in >> ch1) {
	    if (ch1 == ']') return in;
	    in.putback(ch1);
	    in.putback(ch);
	    in.setstate(std::ios::failbit);
	}
    }
	
    return in;
}

std::istream &operator >> (std::istream &in, vector<vector<int>> &vec)
{
    char ch;
    vector<int> tmp;
    vec.clear();

    // Read and check the opening bracket
    in >> ch;
    if (ch != '[') {
	in.putback(ch);
	in.setstate(std::ios::failbit);
	return in;
    }

    // read and store the 1D vectors
    while (in >> tmp) {
	vec.push_back(tmp);
	in >> ch;
	if (ch == ']') break;
	if (ch != ',') {
	    in.putback(ch);
	    in.setstate(std::ios::failbit);
	    break;
	}
    }
    // Check for an empty vector
    if (vec.size() == 0) {
	in.clear();
	char ch1;
	if (in >> ch1) {
	    if (ch1 == ']') return in;
	    in.putback(ch1);
	    in.putback(ch);
	    in.setstate(std::ios::failbit);
	}
    }
    return in;
}

template <class T>
std::ostream & operator << (std::ostream &out, const vector<T> &vec)
{
    out << '[';
    if (vec.size()) {
	out << vec[0];
	for (size_t i=1; i<vec.size(); ++i) {
	    out << ", " << vec[i];
	}
    }
    out << ']';
    return out;
}

int main()
{
    vector<int> v;
    vector<vector<int>> v2;

    while (true) {
	if (cin >> v) {
	    cout << "1D vector: " << v << '\n';
	    continue;
	}
	cin.clear();

	if (cin >> v2) {
	    cout << "2D vector: " << v2 << '\n';
	    continue;
	}
	// If you get here you couldn't read either
	break;
    }
}


Input:
[1, 2, 3]

[[3, 2, 3],
[7, 2, 3],
[9, 2, 3]]


Output:
1D vector: [1, 2, 3]
2D vector: [[3, 2, 3], [7, 2, 3], [9, 2, 3]]


Hello learner999,

Looking at the code that you posted I have some questions.

Is this a C or C++ program?

Do You have a reason for mixing C and C++ code?

Have you learned about "vectors" yet?

Are you expecting to get the file name from the command line or did you have something else in mind?

Is the input file fixed and unchangeable or can you do something different?

It is always best to provide enough code that can be compiled and tested. After that focusing on one part is fine.

Andy
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
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;

bool notNeeded( char c )
{
   string delimiters = "[],";
   return delimiters.find( c ) != string::npos;
}


vector<double> getRow( string &line )
{
   replace_if( line.begin(), line.end(), notNeeded, ' ' );
   stringstream ss1( line );
   vector<double> result;
   for ( double d; ss1 >> d; ) result.push_back( d );
   return result;
}


int main()
{
// ifstream in( "project.dat" );
   istringstream in( "[1, 2, 3]  \n"
                     "           \n"
                     "[[3, 2, 3],\n"
                     " [7, 2, 3],\n"
                     " [9, 2, 3]]\n" );

   string line;
   getline( in, line );
   vector<double> B = getRow( line );

   vector< vector<double> > A;   
   while( getline( in, line ) )
   {
      vector<double> row = getRow( line );
      if ( !row.empty() ) A.push_back( row );
   }

   cout << "Rank 1 array is:\n";
   for ( double d : B ) cout << d << '\t';
   cout << "\n\n";

   cout << "Rank 2 array is:\n";
   for ( auto &row : A ) 
   {
      for ( double d : row ) cout << d << '\t';
      cout << '\n';
   }
}
Here's another version that makes the "read a vector" function a template:
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
#include <iostream>
#include <vector>

using std::vector;
using std::cin;
using std::cout;

template <class T>
std::istream &operator >> (std::istream &in, vector<T> &vec)
{
    char ch;
    T val;
    vec.clear();
    if ((in >> ch ) && ch != '[') {
	in.putback(ch);
	in.setstate(std::ios::failbit);
	return in;
    }

    while (in >> val) {
	vec.push_back(val);
	if (!(in >> ch)) {
	    in.putback(ch);
	    in.setstate(std::ios::failbit);
	    return in;
	}
	if (ch == ']') return in; // success
	if (ch != ',') {
	    in.putback(ch);
	    in.setstate(std::ios::failbit);
	    return in;
	}
    }

    // Check for an empty vector
    if (vec.size() == 0) {
	in.clear();
	char ch1;
	if (in >> ch1) {
	    if (ch1 == ']') return in;
	    in.putback(ch1);
	    in.putback(ch);
	    in.setstate(std::ios::failbit);
	}
    }
	
    return in;
}

template <class T>
std::ostream & operator << (std::ostream &out, const vector<T> &vec)
{
    out << '[';
    if (vec.size()) {
	out << vec[0];
	for (size_t i=1; i<vec.size(); ++i) {
	    out << ", " << vec[i];
	}
    }
    out << ']';
    return out;
}

int main()
{
    vector<int> v;
    vector<vector<int>> v2;

    while (true) {
	if (cin >> v) {
	    cout << "1D vector: " << v << '\n';
	    continue;
	}
	cin.clear();

	if (cin >> v2) {
	    cout << "2D vector: " << v2 << '\n';
	    continue;
	}
	// If you get here you couldn't read either
	break;
    }
}


Hello everyone;Thank you to all of you. I understood well , I learnt how to do it with your comprehensive examples and I solved the problem thank you so mcuh again
Topic archived. No new replies allowed.