Read points from a stream that is only one line - c++

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.

Related

Reading objects into an array from a text file with space delimiter

Good day,
I am trying to read data from a file into an array of objects. I can't seem to find how to tackle the space delimiter. Kindly help me.
The class is called Rational and it has two properties: num and denom.
File data: 1/2 -1/3 3/10 4/5 6/18
So far I have done this:
int operator>>(ifstream& fin, rational r[]) {
fin.open("filedata.txt", ios::in);
if (fin)
{
for (int i = 0; i < 5; i++)
{
fin >> r[i];
}
}
else
{
cout << "\nData file cannot be found!" << endl;
}
}
ifstream& operator>>(ifstream& in, rational& r)
{
int num, denom;
char slash;
in >> num >> slash >> denom;
r.set(num,denom);
return in;
}
Thanks in advance.
The function operator>>(ifstream& in, rational& r) should work as posted although I would change it to
std::istream& operator>>(std::istream& in, rational& r) { ... }
However, the first function is not right. You are not returning anything from the function even though its return type is int. You can change it to:
int operator>>(ifstream& fin, rational r[])
{
int count = 0;
fin.open("filedata.txt", ios::in);
if (fin)
{
for ( ; count < 5; ++count)
{
// If unable to read, break out of the loop.
if ( !(fin >> r[count] )
{
break;
}
}
}
else
{
cout << "\nData file cannot be found!" << endl;
}
return count;
}
Having said that, I think you can improve that function a bit.
Open the file in the calling function, main maybe, and pass the std::ifstream object to it.
Instead of passing it an array, pass it a std::vector. Then, you don't have worry about the number of entries in the file. You read whatever you can find in the file.
Change the return type to be std::istream& so you can chain the calls if necessary.
std::istream& operator>>(std::istream& in, std::vector<rational>& v)
{
rational r;
while ( in >> r )
{
v.push_back(r);
}
return in;
}
In main (or whichever is the higher level function), use:
std::vector<rational> v;
std::ifstream fin("filedata.txt);
if ( !fin )
{
// Deal with error.
}
else
{
fin >> v;
}
// Use v as you see fit.

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

can't I use ifstream in a function that called for istream as a parameter?

This is the drill for Chapter 10 in Programming Principles and Practice Using C++.
The program work with points:
it prompt the user to input (x,y) pairs. They are then stored in a vector of Points called original_points.
the original points are printed to a file
the program then read the file to retrieve the same points, stored in a vector of points called processed_points
the two vectors are compared, if they are not the same, the program throws an error.
The problem is that the processed_points has a size() of 0, that happens only when I use get_vector_points() to get those points. What is wrong with the function?
//put any vector points from ist into points
void get_vector_points(istream& ist, vector<Point>& points)
{
//this function is bad, it doesn't do anything the second time you use it
while(true)
{
Point p;
if( ist >> p)
points.push_back(p);
else return;
}
}
//
void write_to_file(string& path, vector<Point>& v_of_points)
{
//open output file
ofstream ofile(path);
//output results to file
for(Point p : v_of_points)
{
ofile << p <<endl;
}
//close output stream
ofile.close();
}
void read_from_file(string& path, vector<Point>& v_of_points)
{
//open input file
ifstream ifile(path);
//read from file : Here comes trouble
get_vector_points(ifile, v_of_points);
//But no problem if you do the following instead
// while(true)
// {
// Point p;
// if( ifile >> p)
// v_of_points.push_back(p);
// else break;
// }
}
//read point from specified istream ist, format:(0,0)
//output points from specified ostream ost, format:(0,0)
void points_drill(string path)
{
//read from console a vector of points
vector<Point> original_points;
get_vector_points(cin, original_points);
//write the same vector to file
write_to_file(path,original_points);
//read the same vector from file, but call it processed
vector<Point> processed_points;
read_from_file(path,original_points);
//they should be the same
for (int i= 0; i < original_points.size(); i++)
{
if (original_points.size()!=processed_points.size())
throw runtime_error("Size Mismatch"); //error here and proccesed_point has size of 0
if (original_points[i]!=processed_points[i])
throw runtime_error("something is wrong!");
}
}
Note that I'm using a custom Point. Full code is available at http://pastebin.com/ZvfcZxf3
Any comment on the coding style/readability is appreciated.
The call
read_from_file(path,original_points);
is reading into the vector original_points, not processed_points
You should try a different way to read in the file:
void get_vector_points(istream& ist, vector<Point>& points)
{
std::string line;
std::string first, second;
while(std::getline(ist,line))
// this should get every line in the file as a string.
// if the formatting of the file is 2 doubles per line.
// You will need to do the parsing yourself by grabbing each value
{
// example first line: 123 321
first = line.split[0]; // this is not a real function this is just Psudo code
//first = "123"
second = line.split[1];// for parsing text and splitting into 2 doubles
// second = "321"
Point p;
p.x = atoi(first); // atoi is = ascii to int. Makes a string intager into a
p.y = atoi(second);// actual int data type
// p.x = 123 p.y = 321
points.push_back(p)
else return;
}
}
Also, your function get_vector_points will put the input stream to a fail state. You might check EOF and read delimiters (white spaces) to avoid it.
Here with integers:
#include <iostream>
#include <sstream>
#include <vector>
std::istream& get_integers(std::istream& stream, std::vector<int>& integers)
{
int n;
// Read integers and trailing white spaces.
while( ! stream.eof() && stream >> n) {
integers.push_back(n);
stream >> std::ws;
}
return stream;
}
int main()
{
std::istringstream input(" 1 2 3 ");
std::vector<int> integers;
// Read and test the result:
if( ! get_integers(input, integers)) std::cout << "Failure\n";
else {
for(int i : integers)
std::cout << i;
std::cout << '\n';
}
}

Overload stream operator for nested template C++ STL

I've got a data file that is a single line consisting of a nested series of doubles eg.
[[0.127279,0.763675,0.636396],[0.254558,0.890955,0.636396],
[0.127279,0.636396,0.763675],[0.254558,0.763675,0.763675],
[0.381838,0.890955,0.763675],[0.127279,0.509117,0.890955],
[0.254558,0.636396,0.890955],[0.509117,0.890955,0.890955]]
I'd like to be able to read this into a STL vector<vector<double> > using the stream operator which is templated across the inner type of A:
vector<vector<double> > A;
FIN >> A;
I've figured out a way to do this when the vector is not nested, ie. a simple vector<T> as so:
template <class T>
istream& operator>>(istream& s, vector<T> &A){
T x;
string token; char blank;
s >> blank; // Gobble the first '['
while( getline(s, token, ',') ) {
istringstream input(token);
input >> x;
A.push_back(x);
}
s >> blank; // Gobble the last ']'
return s;
}
But I'm having problem with the istream& operator>>(istream& s, vector<vector<T> >&A) part as I can't seem to catch the inner ]'s properly. I'm sure that Boost has a way of doing this, but I'd like to see a solution with the STL for pedagogical purposes.
Note: I'm aware that overloading the stream operator for vector<T> can have far-reaching undesirable consequences and that the implementation should be wrapped up in its own class - I'm using this example above as it stands to clarify the question.
EDIT:
I'd like the method to be robust enough to handle a input array whose size (and inner array) size is not known in advance, but inferred from reading the stream.
Actually, the problem with your code that you want to use the same function for both, when T is:
vector<double>
double
But the logic which needs to read the data into vector and double is slightly different. So you cannot do that, at least not with that simple logic:
I would prefer to write two functions, to handle both cases separately. After all, even in your case, the compiler will generate two different functions for each value of T.
template <class T>
istream& operator>>(istream& s, vector<T> &A)
{
T x;
string token; char blank;
s >> blank; // Gobble the first '['
while( getline(s, token, ',') )
{
istringstream input(token);
input >> x;
A.push_back(x);
}
// s >> blank; // Gobble the last ']'
return s;
}
template <class T>
istream& operator>>(istream& s, vector<vector<T>> &A)
{
vector<T> x;
string token;
char blank;
s >> blank; // Gobble the first '['
while( getline(s, token, ']') )
{
istringstream input(token);
input >> x;
s >> blank; //read , after [...]
A.push_back(x);
x.clear();
}
s >> blank; // Gobble the last ']'
return s;
}
Test code:
int main() {
vector<vector<double>> A;
cin >> A;
for(size_t i = 0 ;i < A.size(); ++i)
{
for(size_t j = 0 ; j < A[i].size(); ++j)
cout << A[i][j] <<" ";
cout << endl;
}
return 0;
}
Input:
[[1,2,3],[4,5,6],
[7,8,9],[10,11,12],
[13,14,15],[16,17,18],
[19,20,21],[22,23,24]]
Output:
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
16 17 18
19 20 21
22 23 24
Online demo : http://ideone.com/iBbmw
In your particular example which is very simple.
Read the whole line into a string.
Replace all [ , ] and , with whitespace character.
Create a simple stringstream with whitespace replaced string.
Now you can have a a simple loop of
double x;
while( stringstreamp >> x )
{
}
And some special logic after reading three doubles to insert them them into a new array.
Some years later, and I was here struggling with the same problem.
Based on your contribution, I developed a modified version of the original template. This one is able to parse multidimensional arrays, even if they are spread across several lines.
template <class T>
istream& operator>>(istream& s, vector<T> &A){
while(true){
T x;
char c = s.peek();
if( c == '[' || c == ','){
s.ignore();
if(s >> x) A.push_back(x);
else throw invalid_argument("Bad, bad JS array!");
continue;
}
if( c == ']') {
s.ignore();
return s;
}
/* Ignore line-break */
s.ignore();
}
return s;
}
Hope this can be useful for someone.

Reading from text files 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);
}