Reading data from file into array - c++

I am trying to read specific data from a file into two 2D arrays. The first line of data defines the size of each array so when I fill the first Array i need to skip that line. After skipping the first line, the first array fills with data from the file until the 7th line in the file. The second array is filled with the rest of the data from the file.
Here's a labeled image of my data file:
and here's my (flawed) code so far:
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ifstream inFile;
int FC_Row, FC_Col, EconRow, EconCol, seat;
inFile.open("Airplane.txt");
inFile >> FC_Row >> FC_Col >> EconRow >> EconCol;
int firstClass[FC_Row][FC_Col];
int economyClass[EconRow][EconCol];
// thanks junjanes
for (int a = 0; a < FC_Row; a++)
for (int b = 0; b < FC_Col; b++)
inFile >> firstClass[a][b] ;
for (int c = 0; c < EconRow; c++)
for (int d = 0; d < EconCol; d++)
inFile >> economyClass[c][d] ;
system("PAUSE");
return EXIT_SUCCESS;
}
Thanks for the input everyone.

Your while loops iterate until the end of file, you don't need them.
while (inFile >> seat) // This reads until the end of the plane.
Use instead (without the while):
for (int a = 0; a < FC_Row; a++) // Read this amount of rows.
for (int b = 0; b < FC_Col; b++) // Read this amount of columns.
inFile >> firstClass[a][b] ; // Reading the next seat here.
Apply the same for economic seats.
Also you might want change arrays into vectors, since variable size arrays are hell.
vector<vector<int> > firstClass(FC_Row, vector<int>(FC_Col)) ;
vector<vector<int> > economyClass(EconRow, vector<int>(EconCol)) ;
You need to #include <vector> to use vectors, their access is identical to arrays.

You need to change the order of the for loops and reading from the file:
for (rows = 0; rows < total_rows; ++ rows)
{
for (col = 0; columns < total_columns; ++cols)
{
input_file >> Economy_Seats[row][column];
}
}
I'll leave checking for EOF and handling of invalid input to the reader.

You're reading into seat once then filling the array with this value. Then you're reading into seat again, and filling the entire array with this new value.
Try this:
int CurRow = 0;
int CurCol = 0;
while ( (inFile >> seat) && (CurRow < FC_Row)) {
firstClass[CurRow][CurCol] = seat;
++CurCol;
if (CurCol == FC_Col) {
++CurRow;
CurCol = 0;
}
}
if (CurRow != FC_Row) {
// Didn't finish reading, inFile >> seat must have failed.
}
Your second loop should use economyClass not firstClass
The reason for switching the loop around like this is error handling, which is simplified when the loop exits upon error. Alternatively you could keep the for loops, use infile >> seat in the inner loop, but you'd then have to break out of two loops if reading failed.

Related

Reading Column Specific Data in C++ [duplicate]

I have a text file that has values and I want to put them into a 2D vector.
I can do it with arrays but I don't know how to do it with vectors.
The vector size should be like vector2D[nColumns][nLines] that I don't know in advance. At the most I can have in the text file the number of columns, but not the number of lines.
The number of columns could be different, from one .txt file to another.
.txt example:
189.53 -1.6700 58.550 33.780 58.867
190.13 -3.4700 56.970 42.190 75.546
190.73 -1.3000 62.360 34.640 56.456
191.33 -1.7600 54.770 35.250 65.470
191.93 -8.7500 58.410 33.900 63.505
with arrays I do it like this:
//------ Declares Array for values ------//
const int nCol = countCols; // read from file
float values[nCol][nLin];
// Fill Array with '-1'
for (int c = 0; c < nCol; c++) {
for (int l = 0; l < nLin; l++) {
values[c][l] = -1;
}
}
// reads file to end of *file*, not line
while (!inFile.eof()) {
for (int y = 0; y < nLin; y++) {
for (int i = 0; i < nCol; i++) {
inFile >> values[i][y];
}
i = 0;
}
}
Instead of using
float values[nCol][nLin];
use
std::vector<std::vector<float>> v;
You have to #include<vector> for this.
Now you don't need to worry about size.
Adding elements is as simple as
std::vector<float> f; f.push_back(7.5); v.push_back(f);
Also do not use .eof() on streams, because it doesn't set it until after the end has been reached and so it will attempt to read the end of the file.
while(!inFile.eof())
Should be
while (inFile >> values[i][y]) // returns true as long as it reads in data to values[x][y]
NOTE: Instead of vector, you can also use std::array, which is apparently the best thing after sliced bread.
My suggestion:
const int nCol = countCols; // read from file
std::vector<std::vector<float>> values; // your entire data-set of values
std::vector<float> line(nCol, -1.0); // create one line of nCol size and fill with -1
// reads file to end of *file*, not line
bool done = false;
while (!done)
{
for (int i = 0; !done && i < nCol; i++)
{
done = !(inFile >> line[i]);
}
values.push_back(line);
}
Now your dataset has:
values.size() // number of lines
and can be adressed with array notation also (besides using iterators):
float v = values[i][j];
Note: this code does not take into account the fact that the last line may have less that nCol data values, and so the end of the line vector will contain wrong values at end of file. You may want to add code to clear the end of the line vector when done becomes false, before you push it into values.

How do online judges pass the input data?

I'm trying to solve this problem from an online judge (Codeforces):
One day Deivis came across two Vectors of integers A and B, and wondered, could it be possible to form the number X by adding an element of A to another element of B?
More formally, it is possible to choose two indexes i and j such that Ai + Bj = x?
Input
The first entry line is two integers n and x. The second line contains n numbers, the vector A. The third and last line contains n numbers, vector B.
Output
Print 1 if it is possible to form the number x from a sum of one element of each vector, and 0 otherwise."
My problem is that I can not fill in the second vector, when the program runs on the site it fills the vector with zeros. I am using C ++, here's my code:
#include <bits/stdc++.h>
using namespace std;
#define MAX 10
int main()
{
int n, x, i = 0, j = 0, resp = 0, sum;
vector<int> vetA(MAX), vetB(MAX);
cin >> n >> x;
while (scanf("%d", &vetA[i]) == 1)
i++;
while (scanf("%d", &vetB[j]) == 1)
j++;
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
sum = vetA[i] + vetB[j];
if (sum == x)
{
resp = 1;
goto END;
}
}
}
END: printf("%d", resp);
return 0;
}
I try to use getchar() after each while loop, but seems that on the site it does not do data capture like on a keyboard, and so the second vector isn't receiving any data. I've also tried to capture data as a std::string but that doesn't work.
Can someone help me?
Here are some hints/examples to compare your program to:
#include <iostream> //Include each standard library seperately
#include <vector> //#include <bits/stdc++.h> is bad practice
// Only declare variables as they are used.
int n; // Better coding practice is one variable per line.
int x; // Competitions shouldn't care how many lines.
if (!(std::cin >> n >> x)) //This is basically the same as cin.fail()
{
std::cerr << "Error inputting data.\n";
return 1;
}
// Now create the vectors, after the size has read in.
std::vector<int> vetA(n);
std::vector<int> vetB(n);
// The number of elements is known, so use a "for" loop.
for (size_t i = 0; i < n; ++i)
{
std::cin >> vetA[i];
}
for (size_t i = 0; i < x; ++i)
{
std::cin >> vetB[i];
}
You should add in some error handling because your program will be given some invalid inputs.
The inputs and vector sizes are examples since you didn't specify the input format in your Post.

Reading values from file into 2D vector results in all values being zero

I'm trying to read a file of integer values and push each value into a 2D vector. For whatever reason, my resulting vector is full of zeros, rather than the values that I just read out of the file. Why is this and how do I fix it?
void populateVector(string file, vector<vector<int>>& v, int rows, int cols){
ifstream read(file);
int val;
if (!read.is_open()) {
throw runtime_error("Output file is not open.");
} else {
//Populate 2D vector with values from file
while (read >> val) {
cout << val << endl; //Prints each value being processed. Prints proper value.
for (int i = 0; i < rows; i++) {
vector<int> newCol;
v.push_back(newCol);
for (int j = 0; j < cols; j++) {
v.at(i).push_back(val);
}
}
}
}
}
When I print the vector it is populated solely of zeros, even though the read values that are printed to standard output are what I expect (the values from the file).
Your solution would push all the numbers 'cols' times into each row, that is you end up with row * (cols * n) matrix. Look at your loops correctly.
I assume you meant to read each number only once. Then change your loop to something like following (add error checking as necessary)
for (int i = 0; i < rows; i++)
{
std::vector<int> newRow;
for (int j = 0; j < cols; j++)
{
int val;
read >> val;
newRow.push_back(val);
}
v.push_back(newRow);
}
If you want to read one value at a time, you may want to consider a loop like this:
unsigned int column = 0;
std::vector<std::vector<int> > matrix;
std::vector<int> data_row;
while (read >> value)
{
data_row.push_back(value);
++column;
if (column > MAXIMUM_COLUMNS)
{
matrix.push_back(row_data);
data_row.clear();
column = 0;
}
}
The above code builds a row of data, one column at a time. When enough columns are read, the row is then appended to the matrix.

Properly handling input when file has less numbers than expected

I'm attempting to read in a file with 3 floating point numbers per line. Right now, I have this implemented as:
std::ifstream inFile(inName.c_str());
if (!inFile) {
prterr("in ASCII file could not be opened!\n");
return -1;
}
std::vector<double> xData, yData, zData;
xData.resize(nPoints);
yData.resize(nPoints);
zData.resize(nPoints);
inFile.precision(std::numeric_limits<double>::digits10+1);
for (int i = 0; i < nPoints; ++i) {
inFile >> xData[i] >> yData[i] >> zData[i];
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
so that the program successfully runs even if the user inputs more than 3 numbers per line. However, sometimes a user tries to run the program with <3 numbers per line. When this happens, the parser will obviously store the data incorrectly.
I would like to either (a) throw an error if the file has less than 3 numbers per line, or (b) Only store the first N numbers per line in their respective vectors if only N numbers per line are present in the file. The trick is, I want to do this as quickly as possible, as my datasets can be several GBs. I can be guaranteed that my file has the exact same amount of numbers per line.
Is there a graceful and efficient way to perform (b)? I know I could implement (a) just by reading the first line as a string separately before the for loop, but that seems quite ugly. Is there a better way to do this?
I know you dd not want to read in the first line as a std::string but you need someway to find out how many white space separated columns there are and unfortunately a newline is treated like white space. If you are okay with doing that though then you can see how man columns you have with
std::ifstream inFile(inName.c_str());
std::vector<int> columns_in_file;
std::string temp;
std::getline(inFile, temp);
std::stringstream ss(temp);
int number;
while (ss >> number)
columns_in_file.push_back(number);
Then what we need to do is set up a 2d vector that will have the correct number of columns and rows.
// get number of columns. 3 max
int columns = columns_in_file.size() <= 3 ? columns_in_file.size() : 3;
std::vector<std::vector<int>> data(nPoints, std::vector<int>(columns));
// now we add the data we already read
for (int i = 0; i < columns; i++)
data[0][i] = columns_in_file[i];
Now we have a vector that is the same size as the file unless the file has more then 3 columns and has the first line of data in it. Now we have a decision to make, since you will only ever need to call
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
while reading if columns_in_file.size() > 3, then we don't want to call it if it is not needed. We could either have the reading code in two different functions or in two different blocks in an else if statement. The latter is what I will show but know you could refactor it into function calls. So to actually read the file we would have something like
if (columns <= 3)
{
for (int i = 0; i < nPoints; i++)
{
for(int j = 0; j < columns; j++)
{
infile >> data[i][j];
}
}
}
else
{
for (int i = 0; i < nPoints; i++)
{
for(int j = 0; j < columns; j++)
{
infile >> data[i][j];
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
}
You can first get the number of columns in the file while reading the first set of values,as a string, and then use the count with another loop inside the first for loop:
[EDIT] As per the comments given(and the learning continues again), instead of making the all vectors resize initially, you can resize them depending on the available columns. this will avoid unnecessary space consumption for the unused vectors.
std::vector<double> Data[3];//the x,y,z data set(Assuming the maximum number of columns can't be >3)
//you can decide which of the vectors(x,y,z) are used by looking at the column count
inFile.precision(std::numeric_limits<double>::digits10+1);
int count=0;//count the number of columns
string first_line;
double temp;
getline(inFile,first_line);
istringstream ss(first_line);
while(ss>>temp && count<3)
{
Data[count].resize(nPoints);
Data[count][0]=temp;
count++;
}
for(int i=1; i<nPoints&& inFile.peek() != EOF ; i++)
{
for(int j=0;j<count;j++)
{
inFile>>temp;
Data[j][i]=temp;
}
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

c++ How can I read values from a .csv file and store them in a vector?

I use Code::Blocks on Windows 7 to make little .exe from .cpp files, and I am a beginner (sorry!)
Here's today's problem:
I have a .csv file containing long integers (from 0 to 2^16) separated by semicolons and listed as a series of horizontal lines.
I will make a simple example here, but in reality the file can be up to 2Go big.
Let's say my file wall.csv appears like this in a text editor such as Notepad++:
350;3240;2292;33364;3206;266;290
362;314;244;2726;24342;2362;310
392;326;248;2546;2438;228;314
378;334;274;2842;308;3232;356
Strangely enough, it appears like this in the windows notepad
350;3240;2292;33364;3206;266;290
362;314;244;2726;24342;2362;310
392;326;248;2546;2438;228;314
378;334;274;2842;308;3232;356
Anyway,
let's say that I will know and will declare in 3 float variables the amount of columns, the amount of lines, and a value from the file.
int col = 7; // amount of columns
int lines = 4; // amount of lines
float x = 0; // a variable that will contain a value from the file
I want:
to create a vector <float> myValues
do myValues.push_back(x) with each value from the 1st line of the csv
do myValues.push_back(x) with each value from the 2nd line of the csv
do myValues.push_back(x) with each value from the 3rd line ...etc.
until the file has been entirely stored in the vector myValues.
My problem:
I don't know how to successively assign to the variable x the values present in the csv file.
How should I do that?
OK this code works (rather slowly but ok!):
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int col = 1221; // amount of columns
int lines = 914; // amount of lines
int x = 0; // a variable that will contain a value from the file
vector <int> myValues;
int main() {
ifstream ifs ("walls.tif.csv");
char dummy;
for (int i = 0; i < lines; ++i){
for (int i = 0; i < col; ++i){
ifs >> x;
myValues.push_back(x);
// So the dummy won't eat digits
if (i < (col - 1))
ifs >> dummy;
}
}
float A = 0;
float B = col*lines;
for (size_t i = 0; i < myValues.size(); ++i){
float C = 100*(A/B);
A++;
// display progress and successive x values
cout << C << "% accomplished, pix = " << myValues[i] <<endl;
}
}
Put the text data into a stringstream and use std::getline.
It takes an optional third parameter which is the "end-of-line" character, but you can use ; instead of a real end of line.
Call
while (std::getline(ss, str, ';')) {..}
and each loop puts the text in std::string.
Then you will need to convert to a number data type and push into a vector but this will get you started.
Also, why do you use floats for the number of columns and lines?
They are integer values.
Try using the C++ Standard Template Library's input operations.
Make a dummy character variable to eat up semicolons, then cin numbers into your x variable like so:
char dummy;
for (int i = 0; i < lines; ++i){
for (int i = 0; i < col; ++i){
cin >> x;
myValues.push_back(x);
// So the dummy won't eat digits
if (i < (col - 1))
cin >> dummy;
}
}
To do it this way, you can redirect your csv file to be input from the command line like so:
yourExecutable.exe < yourFile.csv
To loop through a vector that is filled with data:
for (size_t i = 0; i < myVector.size(); ++i){
cout << myVector[i];
}
Above, the size_t type is defined by the STL library and is used to suppress an error.
If you want to use the values only once, removing them from the container as they are used, you're better off using the std::queue container. This way, you look at the front element using front() and remove it using pop().