Reading Column Specific Data in C++ [duplicate] - c++

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.

Related

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');
}

How do I read text into a 2D array of larger parameters than the text (2D array has more rows and columns) using object.get()?

I am attempting to read a text file of characters into a character array (char array[MAX_ROW][MAX_COL]) and the text file has less rows and columns than the character array. This leads to a problem of reading past the substance material that is within the text file. I run into this problem when I read in using the following method:
ifstream whiteboard; //ifstream object for reading from a file.
whiteboard.open(board_name.c_str());
for(int i = 0; i < MAXROW; i++){ //naive read for canvas, not considering the /n characters or the size of the image.txt
for(int j = 0; j < MAXCOL; j++){ //for this to store the print properly it must be the exact size of the image dimensions
canvas[i][j] = whiteboard.get();
if(whiteboard.get() == '/n'){
return;
}
else if(whiteboard.get() != '/n'){
canvas[i][j] = whiteboard.get();
}
}
}
whiteboard.close();
The code above is supposed to run through the 2d array only to the point where the '/n' character is. Thus, allowing me to enter an array of any size. The newline character is at the end of each line of text in a text file (in the form of an enter keystroke). The read to file stops when a newline has been read. However, I am having issues implementing this correctly. Does anyone have any hints that may help me see this more clearly? Thank you very much!
EDIT:
Input File
xxxxxxxxxxxxxx
x x
x x
x x
x x
x x
xxxxxxxxxxxxxx
I am hoping to input the box above (along with all of its ' ' characters contained within it) into corresponding values of the character array. I wish to stop the read after reading the rightmost column of x's in and after reading the final x (the bottom right). You can see that my problem comes from having an array that is larger than the size of my text box here. I understand I could fix this by equating the character array to have the same dimensions as the text box, but I wish to keep a large enough constant so that I can read in a file of a relatively large size.
I have one solution, do the following:
int n=1025, m=1024, MAX_LINES=1025, i=0, j=0;
char character, Matrix[n][m];
fstream file;
file.open("file.txt", ios::in);
while (file.get(character))// loop executes until the get() function is able to read contents or characters from the file
{
Matrix[n][m]=character; // copy the content of character to matrix[n][m], here n is used to work as lines and m as normal arrays.
m++; // finished copying to matrix[n][m] then m++ else the program will overwrite the contents to the same array.
If (m>=1024)// if string[n][m] reached the limit which is 1024.
{
Matrix[n][m]='\0'; //termimate that line
m=0;// start with a new column
if (n<MAX_LINES)// if n is less than 1024 then
n++;// write to a next line because m can support only 1024 chars.
}
Matrix[n][m]='\0';// this will terminate the whole string not just one line.
file.close();
The Matrix Arrays is filled until the file has contents, but less than 1024x1024 chars, u can increase the chars input from the file but i face problems when taking inn more than 4 kb of data into Matrix...
I hope this helps u, if helps even a bit then +1 vote to my answer pls...
You are looking for something like this:
ifstream whiteboard;
whiteboard.open(board_name);
if ( !whiteboard.is_open() )
{
// do something here...
}
char c;
int row = 0, col = 0;
while ( whiteboard.get( c ) )
{
if ( c == '\n' )
{
row++;
col = 0;
continue;
}
canvas[ row ][ col++ ] = *reinterpret_cast< unsigned char * >( &c );
}
whiteboard.close();
With this code you can fill up your matrix with the content of the file... always supposing the "array" in the file fits in the array canvas[][]
If you aren't restricted to using an array, I wanted to add an alternative solution that would allow your canvas to be dynamically sized.
using std::vector;
std::ifstream whiteboard(board_name);
vector<vector<char>> canvas;
canvas.emplace_back();
// ^ Replace with push_back(vector<char>()); if not using C++11
char c;
while (whiteboard.get(c)) {
if (c == '\n') {
canvas.emplace_back(); // See above
}
else {
canvas.back().push_back(c);
}
}
You can decide to iterate through your canvas by using either range-based for loops or by using an index (iterators work too but are ugly):
// Loop through using range-based for (C++11)
for (auto& row : canvas) {
for (auto& col : row) {
std::cout << col;
}
std::cout << std::endl;
}
// Loop through using index
for (int i = 0; i < canvas.size(); i++) {
for (int j = 0; j < canvas[i].size(); j++) {
std::cout << canvas[i][j];
}
std::cout << std::endl;
}

How can I transfer a text file to array 2D in C++?

How can i transfer a text file(.txt) to array 2D in c++ and this is my source code
fstream fin('textfile.txt', ios::in);
int matrix[n][m]; // n is the number of rows and m is the number of columns
for(int i = 0;i < n; i++){
for(int j = 0; j<m; j++){
fin>>matrix[i][j];
}
}
but how can i detemine n and m for do this,i need your help and your advice, please Join us your perspectives
This solution requires C++11+
If there is no n & m in the file, you must assume that the layout is also in 2D
One Two Three
Four Five Six
Warning:: Untested code.
std::stringstream res;
std::string wordUp;
std::vector<std::string> str;
// the matrix, vector of vector of strings.
std::vector<std::vector<std::string>> matrix;
fstream fin('textfile.txt', ios::in);
int lines = 0;
int words = 0;
// read the file line by line using `getline`
for (std::string line; std::getline(fin, line); ) {
++lines;
// use stringstream to count the number of words (m).
res.str(line); // assign line to res. might also need some reset of good().
while (res.good()) {
res >> wordUp;
str.push_back(wordUp);
++words;
}
matrix.push_back(str);
str.erase(str.begin());
}
So u mean u want to read a file and copy contents to char Matrix[][]??, you can use while loop to read characters, and split every 1024 bytes(1 kb) by lines, i mean do this:
#include <fstream.h>
int main()
{
int n=0, m=0, MAX_LINES=1025, i=0, j=0;
char character, Matrix[1024][1025];
fstream file;
file.open("file.txt", ios::in);
while (file.get(character))// loop executes until the get() function is able to read contents or characters from the file
{
Matrix[n][m]=character; // copy the content of character to matrix[n][m], here n is used to work as lines and m as normal arrays.
m++; // finished copying to matrix[n][m] then m++ else the program will overwrite the contents to the same array.
If (m>=1024)// if string[n][m] reached the limit which is 1024.
{
Matrix[n][m]='\0'; //termimate that line
m=0;// start with a new column
if (n<MAX_LINES)// if n is less than 1024 then
n++;// write to a next line because m can support only 1024 chars.
}
}
Matrix[n][m]='\0';// this will terminate the whole string not just one line.
file.close();
for (i=0; i<1025; i++)
{
for (j=0; j<=1024 || Matrix[i][j]!='\0'; j++)
cout<<Matrix[i][j];
}
return 0;
}
This code will read 1024×1024 chars, but if the txt file is less than 1024(m) characters, the while loop will be exited and Matrix[n][m]='\0'; statement is executed.
EDIT: As asked by David i have written the whole code with main() sorry bro i forget, the bug in the code was the variables n and m were intialised to 1025 and 1024 so the program skips writing to Matrix as the Matrix[1024][1025] cannot store more characters... I think this would help, ok bro...

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().