Reading csv file to vector of doubles - c++

I am trying to read this csv file, let's call it "file.csv", and I'm trying to put it into a vector of double.
This csv contains numbers like:
755673.8431514322,
684085.6737614165,
76023.8121728658,
...
I tried using stringstream, and it successfully input these number to the vector but the input numbers is not like I wanted. Instead, the inputted numbers are
7556373, 684085, 76023.8
How can I read the whole digits without throwing any of it away?
This is my code
vector<long double> mainVector;
int main()
{
ifstream data;
data.open("file.csv");
while (data.good())
{
string line;
stringstream s;
long double db;
getline(data, line, ',');
s << line;
s >> db;
mainVector.push_back(db);
}
}

How to read the whole digits without throwing any of it.
As #user4581301 mentioned in the comments, I guess you are missing std::setprecision() while outputting.
However, you do not need std::stringstream to do the job. Convert line(which is a string directly to double using std::stold and place into the vector directly as follows.
That being said, use of std::stold will make sure not to have wrong input to the vector, by throwing std::invalid_argument exception, if the conversion from string to double was unsuccessful. (Credits to #user4581301)
#include <iostream>
#include <fstream>
#include <vector> // std::vector
#include <string> // std:: stold
#include <iomanip> // std::setprecision
int main()
{
std::vector<long double> mainVector;
std::ifstream data("file.csv");
if(data.is_open())
{
std::string line;
while(std::getline(data, line, ','))
mainVector.emplace_back(std::stold(line));
}
for(const auto ele: mainVector)
std::cout << std::setprecision(16) << ele << std::endl;
// ^^^^^^^^^^^^^^^^^^^^
return 0;
}

Related

C++ Parsing a CSV file into vector of vectors: Loosing string 1st character

I am reading a CSV file into vector of string vectors. I have written code below.
#include<iostream>
#include<fstream>
#include<string>
#include <vector>
#include <fstream>
#include <cmath>
#include <sstream>
using namespace std;
int main()
{
ifstream mesh;
mesh.open("mesh_reference.csv");
vector<vector<string> > point_coordinates;
string line, word;
while (getline(mesh,line))
{
stringstream ss(line);
vector<string> row;
while (getline(ss, word, ','))
{
row.push_back(word);
}
point_coordinates.push_back(row);
}
for(int i=0; i<point_coordinates.size(); i++)
{
for(int j=0; j<3; j++)
cout<<point_coordinates[i][j]<<" ";
cout<<endl;
}
return 0;
}
When I print out the vector of vectors, I see that I am loosing the first character of Element at 0 position in the vector row. Basically, point_coordinates[0][0] is displaying 0.0001 while the string is supposed to be -0.0001. I am not able to understand the reason for the same. Kindly help.
A typical output line is
.0131 -0.019430324 0.051801
Whereas the CSV data is
0.0131,-0.019430324,0.051801
SAMPLE CSV DATA FROM FILE
NODES__X,NODES__Y,NODES__Z
0.0131,-0.019430324,0.051801
0.0131,-0.019430324,0.06699588
0.0131,-0.018630324,0.06699588
0.0131,-0.018630324,0.051801
0.0131,-0.017630324,0.050801
0.0131,-0.017630324,0.050001
0.0149,-0.017630324,0.050001
0.0149,-0.019430324,0.051801
Although the problem is already solved, I would like to show you a solution using some modern C++ algorithms and eliminating minor issues.
Do not use using namespace std;. You should not do this
Ne need for a separate file.open. The std::ifstream constructor will open the file for you. And the destructor will close it
Check if the file could be opened. The ifstreams ! operator is overloaded. So you can do a boolean check
Do not use int in for loops where you compare against .size(). Use ````size_t instead
Always initialize all variables, even if there is an assignement in the next line
For tokenizing you should use std::sregex_token_iterator. It has exactly been designed for this purpose
In modern C++ you are encouraged to use algorithms
Please see an improved version of your code below:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <regex>
const std::regex comma(",");
int main()
{
// Open source file.
std::ifstream mesh("r:\\mesh_reference.csv");
// Here we will store the result
std::vector<std::vector<std::string>> point_coordinates;
// We want to read all lines of the file
std::string line{};
while (mesh && getline(mesh, line)) {
// Tokenize the line and store result in vector. Use range constructor of std::vector
std::vector<std::string> row{ std::sregex_token_iterator(line.begin(),line.end(),comma,-1), std::sregex_token_iterator() };
point_coordinates.push_back(row);
}
// Print result. Go through all lines and then copy line elements to std::cout
std::for_each(point_coordinates.begin(), point_coordinates.end(), [](std::vector<std::string> & vs) {
std::copy(vs.begin(), vs.end(), std::ostream_iterator<std::string>(std::cout, " ")); std::cout << "\n"; });
return 0;
}
Please consider, if you may want to use such an approach in the future

Trouble with parsing text file based on commas (C++)

I am working on creating a program that is supposed to read a text file (ex. dog, buddy,,125,,,cat,,,etc...) line by line and parse it based on commas. This is what I have so far but when I run it, nothing happens. I am not entirely sure what i'm doing wrong and I am fairly new to the higher level concepts.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <cstdlib>
#include <sstream>
#include <vector>
using namespace std;
int main()
{
std::ifstream file_("file.txt"); //open file
std::string line_; //declare line_ as a string
std::stringstream ss(line_); //using line as stringstream
vector<string> result; //declaring vector result
while (file_.is_open() && ss.good())
{ //while the file is open and stringstream is good
std::string substr; //declares substr as a string
getline( ss, substr, ',' ); //getting the stringstream line_ and substr and parsing
result.push_back(substr);
}
return 0;
}
Did you forget to add a line like std::getline(file_, line_);? file_ was not read from at all and line_ was put into ss right after it was declared when it was empty.
I'm not sure why you checked if file_ is open in your loop condition since it will always be open unless you close it.
As far as I know, using good() as a loop condition is not a good idea. The flags will only be set the first time an attempt is made to read past the end of the file (it won't be set if you read to exactly the end of the file when hitting the delimiter), so if there was a comma at the end of the file the loop will run one extra time. Instead, you should somehow put the flag check after the extraction and before you use the result of the extraction. A simple way is to just use the getline() call as your loop condition since the function returns the stream itself, which when cast into a bool is equivalent to !ss.fail(). That way, the loop will not execute if the end of the file is reached without extracting any characters.
By the way, comments like //declaring vector result is pretty much useless since it gives no useful information that you can't easily see from the code.
My code:
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
int main()
{
std::ifstream file("input.txt");
std::string line, word;
std::vector<std::vector<string>> result; //result[i][j] = the jth word in the input of the ith line
while(std::getline(file, line))
{
std::stringstream ss(line);
result.emplace_back();
while(std::getline(ss, word, ','))
{
result.back().push_back(word);
}
}
//printing results
for(auto &i : result)
{
for(auto &j : i)
{
std::cout << j << ' ';
}
std::cout << '\n';
}
}

Ignore spaces in vector C++

I'm trying to split a string in individual words using vector in C++. So I would like to know how to ignore spaces in vector, if user put more than one space between words in string.
How would I do that?
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
cout<<"Sentence: ";
string sentence;
getline(cin,sentence);
vector<string> my;
int start=0;
unsigned int end=sentence.size();
unsigned int temp=0;
while(temp<end){
int te=sentence.find(" ",start);
temp=te;
my.push_back(sentence.substr(start, temp-start));
start=temp+1;
}
unsigned int i;
for(i=0 ; i<my.size() ; i++){
cout<<my[i]<<endl;
}
return 0;
}
Four things:
When reading input from a stream into astring using the overloaded >> operator, then it automatically separates on white-space. I.e. it reads "words".
There exists an input stream that uses a string as the input, std::istringstream.
You can use iterators with streams, like e.g. std::istream_iterator.
std::vector have a constructor taking a pair of iterators.
That means your code could simply be
std::string line;
std::getline(std::cin, line);
std::istringstream istr(line);
std::vector<std::string> words(std::istream_iterator<std::string>(istr),
std::istream_iterator<std::string>());
After this, the vector words will contain all the "words" from the input line.
You can easily print the "words" using std::ostream_iterator and std::copy:
std::copy(begin(words), end(words),
std::ostream_iterator<std::string>(std::cout, "\n"));
The easiest way is to use a std::istringstream like follows:
std::string sentence;
std::getline(std::cin,sentence);
std::istringstream iss(sentence);
std::vector<std::string> my;
std::string word;
while(iss >> word) {
my.push_back(word);
}
Any whitespaces will be ignored and skipped automatically.
You can create the vector directly using the std::istream_iterator which skips white spaces:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
int main() {
std::string str = "Hello World Lorem Ipsum The Quick Brown Fox";
std::istringstream iss(str);
std::vector<std::string> vec {std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>() };
for (const auto& el : vec) {
std::cout << el << '\n';
}
}
Here is a function which divides given sentence into words.
#include <string>
#include <vector>
#include <sstream>
#include <utility>
std::vector<std::string> divideSentence(const std::string& sentence) {
std::stringstream stream(sentence);
std::vector<std::string> words;
std::string word;
while(stream >> word) {
words.push_back(std::move(word));
}
return words;
}
Reducing double, triple etc. spaces in string is a problem you'll encounter again and again. I've always used the following very simple algorithm:
Pseudocode:
while " " in string:
string.replace(" ", " ")
After the while loop, you know your string only has single spaces since multiple consecutive spaces were compressed to singles.
Most languages allow you to search for a substring in a string and most languages have the ability to run string.replace() so it's a useful trick.

How to read an array of complex numbers from a text file in C++

As a learner in c++, I decided to play with complex numbers, using the standard library. Now I need to read and write an array of complex from/to text files. This works simply for writing, without supplemental tricks :
void dump(const char *filename){
ofstream result;
result.open (filename);
for(int k=0;k<15;k++){
result<< outputs[k] <<endl;
}
result.close();
}
The data are parenthesized and written line by line looking like : (real,im)...
Now, I guess reading (and loading an array of complex) should be as trivial as reading. However, despite my research, I have not found the right way to do that.
My first attempt was naive :
void readfile(const char *filename){
string line;
ifstream myfile (filename);
if (myfile.is_open())
{
int k=0;
while ( getline (myfile,line) ){
k++;
cout << line << endl;
inputs[k]= (complex<float>) line; //naive !
}
myfile.close();
}
else cout << "Unable to open file";
}
Is there a way to do that simply (without a string parser ) ?
Assuming you have an operator<< for your_complex_type (as has been mentioned, std::complex provides one), you can use an istream_iterator:
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
std::ifstream input( "numbers.txt" );
std::vector<your_complex_type> buffer{
std::istream_iterator<your_complex_type>(input),
std::istream_iterator<your_complex_type>() };
}
This will read all numbers in the file and store them in an std::vector<your_complex_type>.
Edit about your comment
If you know the number of elements you will read up-front, you can optimize this as follows:
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
std::ifstream input( "numbers.txt" );
std::vector<your_complex_type> buffer;
buffer.reserve(expected_number_of_entries);
std::copy(std::istream_iterator<your_complex_type>(input),
std::istream_iterator<your_complex_type>(),
std::back_inserter(buffer));
}
std::vector::reserve will make the vector reserve enough memory to store the specified number of elements. This will remove unnecessary reallocations.
You can also use similar code to write your numbers to a file:
std::vector<your_complex_type> numbers; // assume this is filled
std::ofstream output{ "numbers.txt" };
std::copy(std::begin(numbers), std::end(numbers),
std::ostream_iterator<your_complex_type>(output, '\n') );
C++ version:
std::complex<int> c;
std::ifstream fin("filename");
fin>>c;
C version:
int a,b;
FILE *fin=fopen("filename","r");
fscanf(fin,"(%d,%d)\n",&a,&b);
C++ read multiple lines with multiple complex values on each line
#include <stdio.h>
#include <fstream>
#include <complex>
#include <iostream>
#include <sstream>
int main ()
{
std::complex<int> c;
std::ifstream fin("test.in");
std::string line;
std::vector<std::complex<int> > vec;
vec.reserve(10000000);
while(std::getline(fin,line))
{
std::stringstream stream(line);
while(stream>>c)
{
vec.push_back(c);
}
}
return 0;
}

read integers from a file into a vector in C++

I am trying to read an unknown number of double values stored on separate lines from a text file into a vector called rainfall. My code won't compile; I am getting the error no match for 'operator>>' in 'inputFile >> rainfall' for the while loop line. I understand how to read in from a file into an array, but we are required to use vectors for this project and I'm not getting it. I appreciate any tips you can give on my partial code below.
vector<double> rainfall; // a vector to hold rainfall data
// open file
ifstream inputFile("/home/shared/data4.txt");
// test file open
if (inputFile) {
int count = 0; // count number of items in the file
// read the elements in the file into a vector
while ( inputFile >> rainfall ) {
rainfall.push_back(count);
++count;
}
// close the file
I think you should store it in a variable of type double. Seems you are doing >> to a vector, which is not valid. Consider the following code:
// open file
ifstream inputFile("/home/shared/data4.txt");
// test file open
if (inputFile) {
double value;
// read the elements in the file into a vector
while ( inputFile >> value ) {
rainfall.push_back(value);
}
// close the file
As #legends2k points out, you don't need to use the variable count. Use rainfall.size() to retrieve the number of items in the vector.
You cannot use >> operator to read in the whole vector. You need to read one item at a time, and push it into the vector:
double v;
while (inputFile >> v) {
rainfall.push_back(v);
}
You do not need to count the entries, because rainfall.size() will give you the exact count.
Finally, the most C++ -ish way of reading a vector is with istream iterators:
// Prepare a pair of iterators to read the data from cin
std::istream_iterator<double> eos;
std::istream_iterator<double> iit(inputFile);
// No loop is necessary, because you can use copy()
std::copy(iit, eos, std::back_inserter(rainfall));
You could also do:
#include <algorithm>
#include <iterator>
...
std::istream_iterator<double> input(inputFile);
std::copy(input, std::istream_iterator<double>(),
std::back_inserter(rainfall));
...
assuming you like the STL.
The input operator >> is not defined for inputting doubles into a std::vector.
Instead construct the std::vector with two tokenizing input iterators for the input file.
Here's an example of how you can do it by using only 2 lines of code:
std::ifstream inputFile{"/home/shared/data4.txt"};
std::vector<double> rainfall{std::istream_iterator<double>{inputFile}, {}};
Another solution is to define the input operator function as:
std::istream& operator>> (std::istream& in, std::vector<double>& v) {
double d;
while (in >> d) {
v.push_back(d);
}
return in;
}
Then you can use it as in your example:
std::vector<double> rainfall;
inputFile >> rainfall;
Consider using this input reader:
#include <iterator>
#include <algorithm>
#include <vector>
#include <iostream>
#include <fstream>
template<typename T>
std::vector<T> parse_stream(std::istream &stream) {
std::vector<T> v;
std::istream_iterator<T> input(stream);
std::copy(input, std::istream_iterator<T>(), std::back_inserter(v));
return v;
}
int main(int argc, char* argv[])
{
std::ifstream input("/home/shared/data4.txt");
std::vector<int> v = parse_stream<int>(input);
for(auto &item: v) {
std::cout << item << std::endl;
}
return 0;
}
It allows you to use other stream types as well and is generic over type read.