I love how in python I can do something like:
points = []
for line in open(\"data.txt\"):
a,b,c = map(float, line.split(\',\'))
points += [(a,b,c)]
<
I`d do something like this:
ifstream f("data.txt");
string str;
while (getline(f, str)) {
Point p;
sscanf(str.c_str(), "%f, %f, %f\n", &p.x, &p.y, &p.z);
points.push_back(p);
}
x,y,z must be floats.
And include:
#include <iostream>
#include <fstream>
Fun with Boost.Tuples:
#include <boost/tuple/tuple_io.hpp>
#include <vector>
#include <fstream>
#include <iostream>
#include <algorithm>
int main() {
using namespace boost::tuples;
typedef boost::tuple<float,float,float> PointT;
std::ifstream f("input.txt");
f >> set_open(' ') >> set_close(' ') >> set_delimiter(',');
std::vector<PointT> v;
std::copy(std::istream_iterator<PointT>(f), std::istream_iterator<PointT>(),
std::back_inserter(v)
);
std::copy(v.begin(), v.end(),
std::ostream_iterator<PointT>(std::cout)
);
return 0;
}
Note that this is not strictly equivalent to the Python code in your question because the tuples don't have to be on separate lines. For example, this:
1,2,3 4,5,6
will give the same output than:
1,2,3
4,5,6
It's up to you to decide if that's a bug or a feature :)
You could read the file from a std::iostream line by line, put each line into a std::string and then use boost::tokenizer to split it. It won't be quite as elegant/short as the python one but a lot easier than reading things in a character at a time...
This answer is based on the previous answer by j_random_hacker and makes use of Boost Spirit.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <boost/spirit.hpp>
using namespace std;
using namespace boost;
using namespace boost::spirit;
struct Point {
double a, b, c;
};
int main(int argc, char **argv)
{
vector<Point> points;
ifstream f("data.txt");
string str;
Point p;
rule<> point_p =
double_p[assign_a(p.a)] >> ','
>> double_p[assign_a(p.b)] >> ','
>> double_p[assign_a(p.c)] ;
while (getline(f, str))
{
parse( str, point_p, space_p );
points.push_back(p);
}
// Do something with points...
return 0;
}
The C++ String Toolkit Library (StrTk) has the following solution to your problem:
#include <string>
#include <deque>
#include "strtk.hpp"
struct point { double x,y,z; }
int main()
{
std::deque<point> points;
point p;
strtk::for_each_line("data.txt",
[&points,&p](const std::string& str)
{
strtk::parse(str,",",p.x,p.y,p.z);
points.push_back(p);
});
return 0;
}
More examples can be found Here
All these good examples aside, in C++ you would normally override the operator >>
for your point type to achieve something like this:
point p;
while (file >> p)
points.push_back(p);
or even:
copy(
istream_iterator<point>(file),
istream_iterator<point>(),
back_inserter(points)
);
The relevant implementation of the operator could look very much like the code by j_random_hacker.