I try to read a large cvs file into Eigen Matrix, below the code found having problem where it can not detect each line of \n in cvs file to create multiple rows in the matrix. (It read entire file with single row). Not sure what's wrong with the code. Can anyone suggest here?
Im also looking for a effective way to read csv file with 10k of rows and 1k of cols. Not so sure the code below will be the best effective way? Very appreciated with your comment.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <istream> //DataFile.fail() function
#include <vector>
#include <set>
#include <string>
using namespace std;
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace Eigen;
void readCSV(istream &input, vector< vector<string> > &output)
{
int a = 0;
int b = 0;
string csvLine;
// read every line from the stream
while( std::getline(input, csvLine) )
{
istringstream csvStream(csvLine);
vector<string> csvColumn;
MatrixXd mv;
string csvElement;
// read every element from the line that is seperated by commas
// and put it into the vector or strings
while( getline(csvStream, csvElement, ' ') )
{
csvColumn.push_back(csvElement);
//mv.push_back(csvElement);
b++;
}
output.push_back(csvColumn);
a++;
}
cout << "a : " << a << " b : " << b << endl; //a doen't detect '\n'
}
int main(int argc, char* argv[])
{
cout<< "ELM" << endl;
//Testing to load dataset from file.
fstream file("Sample3.csv", ios::in);
if(!file.is_open())
{
cout << "File not found!\n";
return 1;
}
MatrixXd m(3,1000);
// typedef to save typing for the following object
typedef vector< vector<string> > csvVector;
csvVector csvData;
readCSV(file, csvData);
// print out read data to prove reading worked
for(csvVector::iterator i = csvData.begin(); i != csvData.end(); ++i)
{
for(vector<string>::iterator j = i->begin(); j != i->end(); ++j)
{
m(i,j) = *j;
cout << *j << ", ";
}
cout << "\n";
}
}
I will also attach a sample cvs file. https://onedrive.live.com/redir?resid=F1507EBE7BF1C5B!117&authkey=!AMzCnpBqxUyF1BA&ithint=file%2ccsv
Here's something you can actually copy-paste
Writing your own "parser"
Pros: lightweight and customizable
Cons: customizable
#include <Eigen/Dense>
#include <vector>
#include <fstream>
using namespace Eigen;
template<typename M>
M load_csv (const std::string & path) {
std::ifstream indata;
indata.open(path);
std::string line;
std::vector<double> values;
uint rows = 0;
while (std::getline(indata, line)) {
std::stringstream lineStream(line);
std::string cell;
while (std::getline(lineStream, cell, ',')) {
values.push_back(std::stod(cell));
}
++rows;
}
return Map<const Matrix<typename M::Scalar, M::RowsAtCompileTime, M::ColsAtCompileTime, RowMajor>>(values.data(), rows, values.size()/rows);
}
Usage:
MatrixXd A = load_csv<MatrixXd>("C:/Users/.../A.csv");
Matrix3d B = load_csv<Matrix3d>("C:/Users/.../B.csv");
VectorXd v = load_csv<VectorXd>("C:/Users/.../v.csv");
Using the armadillo library's parser
Pros: supports other formats as well, not just csv
Cons: extra dependency
#include <armadillo>
template <typename M>
M load_csv_arma (const std::string & path) {
arma::mat X;
X.load(path, arma::csv_ascii);
return Eigen::Map<const M>(X.memptr(), X.n_rows, X.n_cols);
}
Read the CSV file into your vector < vector > as you please (e.g. Lucas's answer). Instead of the vector< vector<string> > construct, use a vector< vector<double> > or even better a simple vector< double >. To assign the vector of vectors to an Eigen matrix efficiently using vector< vector< double > >, use the following:
Eigen::MatrixXcd mat(rows, cols);
for(int i = 0; i < rows; i++)
mat.row(i) = Eigen::Map<Eigen::VectorXd> (csvData[i].data(), cols).cast<complex<double> >();
If you opted to use the vector< double > option, it becomes:
Eigen::MatrixXcd mat(rows, cols);
mat = Eigen::Map<Eigen::VectorXd> (csvData.data(), rows, cols).cast<complex<double> >().transpose();
This will read from a csv file correctly:
std::ifstream indata;
indata.open(filename);
std::string line;
while (getline(indata, line))
{
std::stringstream lineStream(line);
std::string cell;
while (std::getline(lineStream, cell, ','))
{
//Process cell
}
}
Edit: Also, since your csv is full of numbers, make sure to use std::stod or the equivalent conversion once you expect to treat them as such.
Related
I am struggling to write parameters for a function 'readFile' which parameters are - a file name and a 2D vector to which information is copied from the file. The program doesn't throw ANY errors, but it does return just an empty vector. If i copy the code from 'readFile' function to main() function, it does work, but I want to make a seperate function so I can fill vectors with information from different files. Also I will need to pass these arguments for different type of functions with similar structure where I read from a file and copy to a 2D vector, so I really have to figure this out.
'PrintVector' function works fine. Could someone help me?
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
void printVector(vector< vector <float> > v)
{
for (size_t i=0; i<v.size(); ++i)
{
for (size_t j=0; j<v[i].size(); ++j)
{
cout << v[i][j] << "\t";
}
cout << "\n";
}
}
void readFile(char* filename, vector< vector<float> > &rowvector)
{
ifstream myfile(filename, ios::in);
string line;
string field;
vector<float> v; // 1 row
float result; // converted string value is saved in 'result' as a float type
if(myfile.is_open()){
while ( getline(myfile,line) ) // get next line in file
{
v.clear();
stringstream ss(line);
while (getline(ss,field,',')) // comma seperates elements
{
istringstream convert(field);
if ( !(convert >> result) )
result = 0;
v.push_back(result); // add each field to the 1D array
}
rowvector.push_back(v); // add the 1D array to the 2D array
}
}
myfile.close();
}
int main()
{
vector< vector<float> > myvector; // new 2D vector
readFile("test.txt", myvector);
printVector(myvector);
return 0;
}
Any help is much appreciated!
I have an input file that looks like this
1 0 3
2 11 5
3 15 1
4 16 11
and a structure that looks like this
struct numb {
int numb1;
int numb2;
int numb3;
}
and I need to create an array of the struct so that each element of the array holds all three numbers. So
numbArray[0].numb1 == 1
numbArray[0].numb2 == 0
numbArray[0].numb3 == 3
numbArray[1].numb1 == 2
numbArray[1].numb2 == 11
and so on. I've gotten the hang of opening and closing files, finding how many lines there are in a file, and reading a single line from a file, but I do not know how to store individual elements from a line.
My program looks like this so far:
#include <iostream>
#include <fstream>
#include <string>
int main(int argc, char* argv[])
{
ifstream inFile(argv[1]);
int fileLength = 0;
std::string line;
while(std::getline(inFile, line))
{
++fileLength;
}
struct numb {
int numb1;
int numb2;
int numb3;
}
if(inFile.is_open())
{
for(unsigned i = 0; i <= fileLength; i++)
{
//What to do here?
}
}
}
Use getline when you don't have regular structure to the input and need to handle variation between lines. When your input file has regular structure (in this case, there are always three values per line), then simply use the stream extraction operators directly:
#include <iostream>
#include <vector>
struct group
{
int n1;
int n2;
int n3;
};
int main()
{
std::vector<group> groups;
while (std::cin)
{
group line;
line.n1 << std::cin;
line.n2 << std::cin;
line.n3 << std::cin;
groups.push_back(group);
}
}
Express your ideas directly in code as much as possible.
Note I've written the code assuming that the file is in the proper form. If there are too many or too few values per line, then the above code will be confused. However, it is best to code the simplest thing that could possibly work and worry about complexity when you need it. In your example you stated that the input file was well-formed, so there's no need to overcomplicate things.
I recommend using a std::stringstream for this:
#include <iostream>
#include <sstream>
#include <string>
#include <stdio.h>
#include <vector>
struct numb {
int numb1;
int numb2;
int numb3;
};
void populate(std::vector<numb>& my_numbs, std::string line) {
std::stringstream ss(line);
numb my_numb;
ss >> my_numb.numb1 >> my_numb.numb2 >> my_numb.numb3;
my_numbs.push_back(my_numb);
}
void output(const numb my_numbs) {
printf("%d %d %d\n", my_numbs.numb1, my_numbs.numb2, my_numbs.numb3);
}
int main(int argc, char* argv[]) {
ifstream inFile(argv[1]);
std::string line;
std::vector<numb> my_vect;
while(std::getline(inFile, line)) {
populate(my_vect, line);
}
for(size_t i = 0; i < my_vect.size(); ++i) {
std::cout << "my_vect[" << i << "]:";
output(my_vect[i]);
}
return 0;
}
std::stringstreams allow you to parse out data types from std::strings, you you just need to parse out 3 ints, which you can use with your struct. You then push the struct into your vector.
Here's the working ideone taking input from stdin.
You should probably be able to do something like this:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
ifstream inFile(argv[1]);
int fileLength = 0;
std::string line;
struct numb {
int numb1;
int numb2;
int numb3;
};
vector<vector<int>> sets;
int n1, n2, n3;
while (std::cin >> n1)
{
cin >> n2;
cin >> n3;
vector<int> vec;
vec.push_back(n1);
vec.push_back(n2);
vec.push_back(n3);
sets.push_back(vec);
}
numb * numbSet = new numb[sets.size()];
//Since the vectors data is continuous in memory just as the array of structs are
//you can just copy the data directly
for (int i = 0; i < sets.size(); i++)
{
std::memcpy(&numbSet[i], &sets[i][0], sizeof(numb));
}
}
I am reading numbers from a file, say:
1 2 3 4 5
I want to read this data from a file into a string into an array for further processing. Here's what I've done:
float *ar = nullptr;
while (getline(inFile, line))
{
ar = new float[line.length()];
for (unsigned int i = 0; i < line.length(); i++)
{
stringstream ss(line);
ss >> ar[i];
}
}
unsigned int arsize = sizeof(ar) / sizeof(ar[0]);
delete ar;
Suffice it to say that it works insofar it only gets the first value from the file. How do I get the array to be input ALL the values? I debugged the program and I can confirm that line has all the necessary values; but the float array doesn't. Please help, thanks!
line.length() is the number of characters in the line, not the number of words/numbers/whatevers.
Use a vector, which can be easily resized, rather than trying to juggle pointers.
std::vector<float> ar;
std::stringstream ss(line);
float value;
while (ss >> value) { // or (inFile >> value) if you don't care about lines
ar.push_back(value);
}
The size is now available as ar.size(); your use of sizeof wouldn't work since ar is a pointer, not an array.
The easiest option is to use the standard library and its streams.
$ cat test.data
1.2 2.4 3 4 5
Given the file you can use the stream library like this:
#include <fstream>
#include <vector>
#include <iostream>
int main(int argc, char *argv[]) {
std::ifstream file("./test.data", std::ios::in);
std::vector<float> res(std::istream_iterator<float>(file),
(std::istream_iterator<float>()));
// and print it to the standard out
std::copy(std::begin(res), std::end(res),
std::ostream_iterator<float>(std::cout, "\n"));
return 0;
}
I ran into this problem earlier when I wanted to extract data line by line from a file to fill my sql database that I wanted to use.
There are many solutions to this specific problem such as:
The solution is using stringstream with a while statement to put data from file into the array with a while statement
//EDIT
While statement with getline
//This solution isn't very complex and is pretty easy to use.
New Improved simple solution:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main()
{
ifstream line;
line.open("__FILENAME__");
string s;
vector<string> lines;
while(getline(line, s))
{
lines.push_back(s);
}
for(int i = 0;i < lines.size();i++)
{
cout << lines[i] << " ";
}
return 0;
}
compiled code to check - http://ideone.com/kBX45a
What about atof?
std::string value = "1.5";
auto converted = atof ( value.c_str() );
Rather complete:
while ( std::getline ( string ) )
{
std::vector < std::string > splitted;
boost::split ( splitted, line, boost::is_any_of ( " " ) );
std::vector < double > values;
for ( auto const& str: splitted ) {
auto value = atof ( str.c_str() );
values.push_back ( value );
}
}
I'm making a function importcsv() which takes in a filename and outputs a 2D array. For some reason, whenever I use the following version of importcsv(), the compiler runs smoothly, but the executable always returns a "segmentation fault: 11" error.
typedef vector<vector<double> > matrix;
matrix importcsv(string filename)
{
ifstream myfile (filename); //Constructs a stream, and then asssociates the stream with the file "filename"
matrix contents; // Vector which will store the contents of the stream.
int i, j;
while(!myfile.eof())
{
if(myfile.get()==','){++j;}
else if(myfile.get()=='\n'){++i; j=0;}
else{
contents[i][j]=2;}
}
return contents;
}
Can anyone find the source of the error? btw I have the following header:
#include <fstream>
#include <iostream>
#include <array>
#include <vector>
using namespace std;
You are getting "segmentation fault: 11" since you have not allocated memory for contents.
contents[i][j] will work only if contents has something in it.
You can divide reading of the file and constructing the matrix into various parts:
Reading all the numbers in a line and treating it as a row of contents.
Reading a number from the line and treating it as a column of a row.
This way, the program can be simplified. This also helps you easily isolate problems when there are any and fix them.
typedef vector<vector<double> > matrix;
double readNextNumber(std::istream& str)
{
double n = 0.0;
str >> n;
// Skip until we get ',' or '\n'
while (str)
{
int c = str.getc();
if ( c == ',' || c == '\n' || c == EOF )
break;
}
return n;
}
std::vector<double> importRow(std::ifstram& myfile)
{
std::string line;
std::vector<double> row;
// Read a line as a string.
// Then parse the string using std::istringstream.
// When you have finished parsing the line, you know
// you have finished constructing a row of the matrix.
std::getline(myfile, line);
if ( myfile )
{
std::istringstream str(line);
while (str)
{
double n = readNextNumber(str);
if (str)
{
row.push_back(n);
}
}
}
return row;
}
matrix importcsv(string filename)
{
ifstream myfile (filename); //Constructs a stream, and then asssociates the stream with the file "filename"
matrix contents; // Vector which will store the contents of the stream.
while(!myfile.eof())
{
std::vector<double> row = importRow(myfile);
if (myfile)
{
contents.push_back(row);
}
}
return contents;
}
You haven't defined the size of contents. So by default, it will be a vector of 0 element. Therefore the calls to the operator[] will lead to a segmentatin fault.
Implementing the advice of the others here, the quick fix is to use resize() before reading each value into the array:
//WARNING: THIS PROGRAM UTILIZES C++11
#include <fstream>
#include <iostream>
#include <array>
#include <vector>
#include <cctype>
#include <thread>
using namespace std;
typedef vector<vector<double> > matrix;
matrix importcsv(string filename)
{
ifstream myfile ("wavelengthtorgb.csv"); //Constructs a stream, and then asssociates the stream with the file "filename".
matrix contents {{0.0}};
char nextchar; double data; int i,j;
while(!myfile.eof())
{
myfile.get(nextchar);
if(nextchar==',')
{
++j;
contents[i].resize(j+1);
cout<<"encountered a comma."<<" contents is now " <<i+1<<" x "<<j+1<<'\n';
}
else if(isspace(nextchar))
{
myfile.get(); //You might not need this line - first run with this line, and if there is an error, delete it, and try again.
++i;
contents.resize(i+1);
j=0;
contents[i].resize(j+1);
cout<<"encountered a carriage return."<<" contents is now " <<i+1<<" x "<<j+1<<'\n';
}
else
{
myfile.unget();
myfile >> data;
contents[i][j]=data;
cout<< "encountered a double."<<" contents("<<i<<','<<j<<")="<<data<<'\n';
}
}
return contents;
}
I save a boolean matrix(ROW*ROW) to .txt file (0,1 format).
How could I read the matrix from the file? I wrote code below, but I compare the read results with the file, and the array results don't match the file. Could anyone tell me where I wrote wrong? Or are there any easier ways to read a matrix file?
bool **results = new bool*[ROW];
for(int i=0;i<ROW;i++){
results[i] = new bool[ROW];
}
ifstream infile;
infile.open ("FRM.txt");
string line;
int row=0;
if (infile.is_open())
{
while ( infile.good() )
{
getline(infile,line);
istringstream iss(line);
int col=0;
while(iss)
{
string word;
iss >> word;
int number = atoi(word.c_str());
if(number==1){
results[row][col] = true;
}
else{
results[row][col] = false;
}
col++;
}
row++;
}
}
infile.close();
Representing a matrix as a nested array is usually a bad idea. Use a linear array instead and do the index-juggling through a macro or inline function.
I would go for something like this:
#include <algorithm>
#include <cmath>
#include <cstdint> // uint8_t requires C++11
#include <iterator>
#include <vector>
// don't use vector<bool>, it creates all sorts of problems
std::vector<uint8_t> results;
{
std::ifstream infile('FRM.txt', std::ifstream::in);
if(infile.is_open() && infile.good())
{
std::istream_iterator<uint8_t> first(infile), last;
copy(first, last, std::back_inserter(results));
}
}
// only if you know the matrix is square! error checking strongly advised!
size_t nrows = size_t(std::sqrt(results.size()));
// accessing element (i,j) is then as easy as
size_t i = 2, j = 3; // assuming nrows > i,j
bool a_ij = results[i*rows+j];