Reading from text files C++ - c++

I have a text file containing three columns of numbers; one column each for the x,y,z coordinates of a bunch of points. All numbers are between 0 and 1.
I have created the following structure:
typedef struct
{
double xcd, ycd, zcd;
} point;
I want to create a size-N array of structures of type point. Then I want to scan the text file line by line and for the nth particle, I want to put in the three numbers on the nth line into the respective xcd, ycd and zcd positions.
Tell me if there is some efficeint way of going about this.

Simply do it like has been shown five million billion kajillion times before, using ifstream, vector and various other accouterments.
ifstream infile("myfile.txt");
// check if file opened successfully
if (!infile) {
cerr << "failure, can't open file" << endl;
cin.get();
return EXIT_FAILURE;
}
// the container in which we will store all the points
vector<point> points;
// a temporary point to hold the three coords in while we read them all
point tmp;
// read in three doubles from infile into the three coords in tmp
while (infile >> tmp.xcd && infile >> tmp.ycd && infile >> tmp.zcd)
// add a copy of tmp to points
points.push_back(tmp);
This will read in three doubles and put them in a point then put a copy of that point in points. However, if the number of numbers in the file modulus 3 is not 0, it will stop and not add the incomplete point to points.

Use a std::fstream.
If you're sure that the file is correct:
struct Point {
double xcd, ycd, zcd;
};
// btw this is how you should declare a structure in C++,
// the way you shown is rather characteristic to C and only used there
Point tab[N];
void foo() {
std::ifstream f("file.txt");
for (int i=0; i<N; ++i) {
f >> tab[i].xcd >> tab[i].ycd >> tab[i].zcd;
}
}
If you're not sure that the file will exist and contain exactly this number of particles, you should check for f.fail() after each a read attempt.

I prefer using the standard generic algorithms to writing my own loops:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <fstream>
typedef struct
{
double xcd, ycd, zcd;
} point;
std::istream& operator>>(std::istream&is, point& pt)
{
return is >> pt.xcd >> pt.ycd >> pt.zcd;
}
int main(int ac, char **av) {
std::ifstream f("file.txt");
std::vector<point> v;
std::copy(
std::istream_iterator<point>(f),
std::istream_iterator<point>(),
std::back_inserter(v));
}

Another design is to overload the stream extraction operator in your point structure:
struct Point
{
double x;
double y;
double z;
friend istream& operator>>(istream& inp, Point& p);
}
istream& operator>>(istream& inp, Point& p)
{
inp >> x;
inp >> y;
inp >> z;
inp.ignore(100000, '\n');
return inp;
}
Usage:
ifstream myfile("data.txt");
Point p;
vector<Point> point_container;
while (myfile >> p)
{
point_container.push_back(p);
}

Related

Read points from a stream that is only one line

I have a file which first tells me how many points will I be reading on the following line. So, for example my file look like this:
7
a,b c,d e,f g,h, i,j k,l m,n
So I know the following line after 7 is 7 pairs of integers separated by a comma and each pair separated by a blank space.
What I want: To have a vector of 7 Point elements.
I have a class called Point:
class Point {
public:
int x;
int y;
bool operator==(const Point q){
return (q.x == this->x && q.y == this->y);
}
};
So when I read this file I'd like to have a vector V where:
V[0].x = a
V[0].y = b
V[1].x = c
V[1].y = d
and so on.
I can read the 7 fine, but how do I read each of the 7 pairs of integers individually? I need this because I'm going to store (a,b) (c,d)... in a vector.
Is not only 2 points. The first line of the file tells me how many points I'm going to store.
They're not read from standard input.
They're read from a file.
I tried using sscanf but I think that's only for when you have multiple lines with this info and I'd like to not have to modify my format.
This is what I have so far:
void process_file(string filename){
ifstream thracklefile;
string line;
int set_size;
thracklefile.open(filename);
getline(thracklefile,line); //store set size.
set_size = stoi(line);
//Store points in following line
points.clear();
points.resize(set_size);
getline(thracklefile,line); //store the points.
}
I do not want to ignore commas, each comma is part of the information I want to store for each Point.
I think most of the discussion in the comments is about semantics. It is recommended you "ignore" the commas but you can't do that as they are in the file. Perhaps a better term is "discard". The word "ignore" is use since there is a C++ iostream function ignore.
There are many ways to handle this. One option is to override the stream insertion/extraction operators:
class Point {
public:
int x;
int y;
// Don't really need this as members are public, but
// in case you change that in the future....
friend istream& operator>>(istream& in, Point& p);
friend ostream& operator<<(ostream& out, const Point& p);
};
istream& operator>>(istream& in, Point& p)
{
char separator;
// Try to read <int><char><int>
in >> p.x >> separator >> p.y;
// The stream may be in an error state here. That
// is ok. Let the caller handle that
// Also note that we discard (ignore) "separator"
return in;
}
ostream& operator<<(ostream& out, const Point& p)
{
out << p.x << ',' << p.y;
return out;
}
int main() {
int num_points;
std::cin >> num_points;
Point p;
for (int i = 0; i < num_points; i++) {
if (!(std::cin >> p)) {
// There was an error
std::cout << "File format error!" << std::endl;
break;
}
std::cout << p << std::endl;
}
return 0;
}
The example uses cin but any stream should work, including ifstream.

How to assign each row of a text file to a new vector?

I am C++ noob, I have a text file with 4 rows and 3 columns, where each row corresponds to a sensor signal. How do I load each row to a separate vector<float>?
(0.165334,0) (0.166524,-0.0136064) (-0.144899,0.0207161)
(0.205171,0) (0.205084,-0.0139042) (-0.205263,0.0262445)
(0.216684,0) (0.215388,-0.0131107) (-0.193696,0.0251303)
(0.220137,0) (0.218849,-0.0135667) (-0.194153,0.025175)
This is what I have so far, but this code loads data as string. I want to load my final data as vector<vector<float>>?
vector<vector<string> > input;
ifstream fileFFT(Filename.c_str());
string line;
while(getline(fileFFT, line)){
if(line.empty()){
continue;
}
stringstream row(line);
vector<string> values((istream_iterator<string>(row)),(istream_iterator<string>())); //end
input.push_back(values);
}
Here's something to get you started:
class Point
{
public:
double x;
double y;
friend std::istream& operator>>(std::istream& input, Point& p);
};
std::istream& operator>>(std::istream& input, Point& p)
{
char c;
input >> c; // Read open parenthesis
input >> p.x;
input >> c; // Read comma
input >> p.y;
input >> c; // Read closing parenthesis
return input;
};
//...
std::string row_text;
std::vector<std::vector<Point>> matrix;
while (std::getline(my_file, row_text))
{
std::vector<Point> row;
std::istringstream(row_text);
Point p;
while (row_text >> p)
{
row.push_back(p);
}
matrix.push_back(row);
}
I've created a Point class to represent the pair of floating point numbers.
I also overloaded operator>> to make reading a Point easier.
The loop reads one record or text line, then creates a vector of Point from the text line.
The record or row is then appended to the matrix.
You have half the answer already - use std::getline() to read each line, and then use std::(i)stringstream to process each line.
Now, what you are missing is the other half - parsing each line. And since you already know how to use std::istream_iterator, I would do something like this:
typedef std::pair<float, float> SensorValue;
typedef std::vector<SensorValue> SensorValues;
std::istream& operator>>(std::istream &in, SensorValue &out)
{
float f1, f2;
char ch1, ch2, ch3;
if (in >> ch1 >> f1 >> ch2 >> f2 >> ch3)
{
if ((ch1 == '(') && (ch2 == ',') && (ch3 == ')'))
out = std::make_pair(f1, f2);
else
in.setstate(std::ios_base::failbit);
}
return in;
}
...
std::vector<SensorValues> input;
std::ifstream fileFFT(Filename.c_str());
std::string line;
while (std::getline(fileFFT, line))
{
if (line.empty())
continue;
std::istringstream row(line);
SensorValues values;
std::copy(std::istream_iterator<SensorValue>(row), std::istream_iterator<SensorValue>(), std::back_inserter(values));
input.push_back(values);
}

Reading an Input File And Store The Data Into an Array (beginner)!

The Input file:
1 4 red
2 0 blue
3 1 white
4 2 green
5 2 black
what I want to do is take every row and store it into 2D array.
for example:
array[0][0] = 1
array[0][1] = 4
array[0][2] = red
array[1][0] = 2
array[1][1] = 0
array[1][2] = blue
etc..
code Iam working on it:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int convert_str_to_int(const string& str) {
int val;
stringstream ss;
ss << str;
ss >> val;
return val;
}
string getid(string str){
istringstream iss(str);
string pid;
iss >> pid;
return pid;
}
string getnumberofcolors(string str){
istringstream iss(str);
string pid,c;
iss >> pid>>c;
return c;
}
int main() {
string lineinfile ;
vector<string> lines;
ifstream infile("myinputfile.txt");
if ( infile ) {
while ( getline( infile , lineinfile ) ) {
lines.push_back(lineinfile);
}
}
//first line - number of items
int numofitems = convert_str_to_int(lines[0]);
//lopps items info
string ar[numofitems ][3];
int i = 1;
while(i<=numofitems ){
ar[i][0] = getid(lines[i]);
i++;
}
while(i<=numofitems ){
ar[i][1] = getarrivel(lines[i]);
i++;
}
infile.close( ) ;
return 0 ;
}
when I add the second while loop my program stopped working for some reason!
is there any other way to to this or a solution to my program to fix it.
It's better to show you how to do it much better:
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main() {
ifstream infile("myinputfile.txt"); // Streams skip spaces and line breaks
//first line - number of items
size_t numofitems;
infile >> numofitems;
//lopps items info
vector<pair<int, pair<int, string>> ar(numofitems); // Or use std::tuple
for(size_t i = 0; i < numofitems; ++i){
infile >> ar[i].first >> ar[i].second.first >> ar[i].second.second;
}
// infile.close( ) ; // Not needed -- closed automatically
return 0 ;
}
You are probably solving some kind of simple algorithmic task. Take a look at std::pair and std::tuple, which are useful not only as container for two elements, but because of their natural comparison operators.
The answer given is indeed a much better solution than your's. I figured i should point out some of your design flaws and give some tips too improve it.
You redefined a function that already exists in the standard, which is
std::stoi() to convert a string to an integer. Remember, if a function
exists already, it's OK to reuse it, don't think you have to reinvent what's
already been invented. If you're not sure search your favorite c++ reference guide.
The solution stores the data "as is" while you store it as a full string. This doesn't really make sense. You know what the data is beforehand, use that to your advantage. Plus, when you store a line of data like that it must be parsed, converted, and then constructed before it can be used in any way, whereas in the solution the data is constructed once and only once.
Because the format of the data is known beforehand an even better way to load the information is by defining a structure, along with input/output operators. This would look something like this:
struct MyData
{
int num1;
int num2;
std::string color;
friend std::ostream& operator << (std::ostream& os, const MyData& d);
friend std::istream& operator >> (std::istream& os, const MyData& d);
};
Then you could simply do something like this:
...
MyData tmp;
outfile << tmp;
vData.push_back(tmp);
...
Their is no question of intent, we are obviously reading a data type from a stream and storing it in a container. If anything, it's clearer as to what you are doing than either your original solution or the provided one.

Remove entire rows with missing values c++

I am reading the data with different variables by the following codes, currently when the program touches missing values (represented in data by string "NA", it will change them to zero. Alternatively, I wonder if how can we remove entire rows when program touch "NA". I have tried to look for the same question but they all are for R, not C++. Please, if you can give me some advises. Thanks
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
struct Data {
vector<double> cow_id;
vector<double> age_obs;
vector<double> dim_obs;
vector<double> my_obs;
vector<double> mcf_obs;
vector<double> mcp_obs;
vector<double> mcl_obs;
vector<double> bw_obs;
vector<double> bcs_obs;
double get_number (string value)
{
if (value == "NA")
{return 0.0;}
else
{
istringstream iss (value);
double val;
iss>>val;
return val;
}
}
void read_input (const string filepath)
{
ifstream data_in (filepath.c_str());
if (!data_in)
{cout<<"Failed to open"<<endl;}
else
{
// Read tokens as strings.
string id, age, dim, my, mcf, mcp, mcl, bw, bcs;
string dummy_line;
getline(data_in, dummy_line);
string line;
while (data_in >> id >> age >> dim >> my >> mcf >> mcp >> mcl >> bw >> bcs)
{
// Get the number from the string and add to the vectors.
cow_id.push_back(get_number(id));
age_obs.push_back(get_number(age));
dim_obs.push_back(get_number(dim));
my_obs.push_back(get_number(my));
mcf_obs.push_back(get_number(mcf));
mcp_obs.push_back(get_number(mcp));
mcl_obs.push_back(get_number(mcl));
bw_obs.push_back(get_number(bw));
bcs_obs.push_back(get_number(bcs));
}
data_in.close();
}
size_t size=age_obs.size();
for (size_t i=0; i<size; i++)
{
cout<<cow_id[i]<<'\t'<<age_obs[i]<<'\t'<<dim_obs[i]<<'\t'<<my_obs[i] <<'\t'<<mcf_obs[i]<<'\t'<<mcp_obs[i]<<'\t'<<mcl_obs[i]<<'\t'<<bw_obs[i] <<'\t'<<bcs_obs[i]<<endl;
}
};
int main()
{
Data input;
input.read_input("C:\\Data\\C++\\learncpp\\data.txt");
}
Let's talk tables here.
Tables are containers of records (rows). The data you are capturing from your input file is already organized into records. So the obvious model is to use a structure that matches your file's data records.
struct Record
{
unsigned int cow_id;
unsigned int age_obs;
unsigned int dim_obs;
// ...
};
Your table could be represented as:
std::vector<record> my_table;
So to remove a record from the table, you can use the std::vector::erase() method. Easy. Also, you can use the std::find() function to search the table.
Let's relieve some reader's headaches with your present code by introducing a concept of the record loading its members from the file.
Reading a record from a file is best performed by overloading the stream extraction operator>>:
struct Record
{
//...
friend std::istream& operator>>(std::istream& input, Record& r);
};
std::istream&
operator>>(std::istream& input, Record& r)
{
std::string record_text;
std::getline(input, record_text);
// Extract a field from the record text and check for NA,
// Assign fields of r to those values:
r.cow_id = value;
// Etc.
return input;
}
With the overloaded operator, your input looks like:
Record r;
while (input_file >> r)
{
table.push_back(r);
}
Elegant and simple (reducing injection of defects).

Reading from file into a vector

I'm using C++ and I'm reading from a file lines like this:
D x1 x2 x3 y1
My code has:
struct gate {
char name;
vector <string> inputs;
string output;
};
In the main function:
vector <gate> eco;
int c=0;
int n=0;
int x = line.length();
while(netlist[c][0])
{
eco.push_back(gate());
eco[n].name = netlist[c][0];
eco[n].output[0] = netlist[c][x-2];
eco[n].output[1] = netlist[c][x-1];
}
where netlist is a 2D array I have copied the file into.
I need help to loop over the inputs and save them in the vector eco.
I don’t fully understand the sense of the 2D array but I suspect it’s redundant. You should use this code:
ifstream somefile(path);
vector<gate> eco;
gate g;
while (somefile >> g)
eco.push_back(g);
// or, simpler, requiring #include <iterator>
vector<gate> eco(std::istream_iterator<gate>(somefile),
std::istream_iterator<gate>());
And overload operator >> appropriately for your type gate:
std::istream& operator >>(std::istream& in, gate& value) {
// Error checking … return as soon as a failure is encountered.
if (not (in >> gate.name))
return in;
gate.inputs.resize(3);
return in >> gate.inputs[0] >>
gate.inputs[1] >>
gate.inputs[2] >>
gate.output;
}