Reading a input file into a vector - c++

I'm trying to read a file of int's and double's into a vector but I am having difficulty doing so. Given something like:
1 2.1 3 4
2 4
3
9 0.1
How can I use ifstream and the getline function to convert the string into integers and doubles & inserting this into a vector?
I know this is incorrect but I am thinking of something along the lines of:
vector<Pair *> vec; //Pair is a class that contains a int & a double data member
string str;
double num;
ifstream f;
f.open("name of file");
while(getline(f, str){
num = stod(str);
}
To insert into the vector I believe I can do something along the lines of:
Pair * pairObj = new Pair(x,y); //"x" being of type int and "y" being of type double
v.push_back(pair);
I'm sorry if this is unclear, please let me know and I will do my best to explain myself.

You should just use stream iterators!
#include <iostream> // for IO
#include <vector> // for vector!
#include <iterator> // for stream iterator
#include <algorithm> // for copy (optional)
if you are directly initializing
vector<double>vdata{istream_iterator<double>(ifile),
istream_iterator<double>()};
else use copy or copy_n if you only want a fixed amount of data
copy(istream_iterator<double>(ifile),
istream_iterator<double(),
back_inserter(vdata));
if you are working with a large file i would recommend using this method
vector<doube>vdata;
// this will save alot of time, if you don't resize the vector must keep reallocating data
vdata.reserve(file_size);
copy(istream_iterator<double>(ifile),
istream_iterator<double>(),
back_inserter(vdata));

strtod() is C. Proper C++ uses the >> operator.
Once you have read each line of text, construct a std::istringstream from the string, then use operator>> to parse it.
Something along these line::
std::ifstream f("name of file");
// Check if the file was succesfully opened, etc...
std::string str;
while( getline(f, str))
{
std::istringstream i(str);
std::vector<double> v;
double d;
while (i >> d)
{
v.push_back(d);
}
if (!i.eof())
{
// Must be a parsing failure, deal with it in some way.
}
else
{
// Otherwise, v is the vector of numbers on this line.
}
}

string str;
std::vector< double> vd;
// loop reading lines of input
while( getline( f, str )
{
std::stringstream sst(str);
std::string a;
// loop reading space separated values in line
while( getline( sst, a, ' ' ) )
// conver to double and add to end of vectior
vd.push_back( stod( a );
}
// check for complete pairs
if( vd.size() % 2 )
cout << "Error!"
// loop over pairs
vector< pair<int,double> > vpairs;
for( int kp = 0; kp < vd.size()/2; kp++ )
vpairs.push_back( pair<int,double>( (int)vd[kp*2],vd[kp*2+1) );

Related

how to insert space separated input into an array in C++ [duplicate]

A String is given as an input which consists of numbers and I want to convert it into integer arrays in C++.
#include <string>
#include <iostream>
#include <sstream>
using std::string;
using std::stringstream;
using std::cout;
using std::endl;
int main(int argc,char** argv) {
string num="-24 2 90 24 50 76";
stringstream stream(num);
while(stream){
int n;
stream>>n;
cout<<n<<endl;
}
return 0;
}
Output(GCC) :
-24 2 90 24 50 76 76
Why am i getting extra value and what is the efficient to convert them into integer array ?
UPDATE:
What if the string stream contains delimiter other than space, How to parse this?
For eg:
string num="-24,2,90,24,50,76";
The end of file condition is not set upon a succesful parse, you have to check the state of the stream after parsing.
The second 76 is basically just pure chance. An unsuccesful parse leaves the target operand untouched, and because you did not initialize n, it can be anything.
A quickfix:
stream>>n;
if (stream)
cout<<n<<endl;
A cleaner fix:
int n;
while(stream >> n){
cout<<n<<endl;
}
To store those integers, the canonical way is to use std::vector if the number of elements is unknown. An example usage:
std::vector<int> values;
int n;
while(stream >> n){
...do something with n...
values.push_back(n);
}
However, you can use iterators over streams and use the following:
// Use std::vector's range constructor
std::vector<int> values(
(std::istream_iterator<int>(stream)), // begin
(std::istream_iterator<int>())); // end
Another means of dealing with a character separated integers list using a vector, which is even perhaps a little more simplistic is more like this:
string str = "50,2,25,38,9,16";
vector<int> ints;
stringstream ss(str);
int n;
char ch;
while(ss >> n) {
if(ss >> ch)
ints.push_back(n);
else
ints.push_back(n);
}
that way you can move past any character separations (if they exist) first and then default back to grabbing the integers and adding them to the list if they don't (AKA the end of the list)
i don't know if you find the answer for your updated question or not. if you don't you can easily do it by the code
for (string::iterator it = num.begin(); it != num.end(); ++it) {
if (*it == ',') {
*it = ' ';
}
else continue;
}
this code removes all your colons and replaces them by space. then you can do just normally

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.

Reading numbers from file to string to array

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

segmentation fault 11 error while importing csv

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

Converting string to char and int data types

I've populated a string vector with with numbers and characters (*,+,-,/). I want to assign each number and character to two new vector, and int vector and a char vector. Is there a way to convert the everything from string to the desired data type?
You can use string stream in the <sstream> header.
string myString = "123";
stringstream sStream( myString );
int convertedInt;
sStream >> convertedInt.
Include the <sstream> header and you can do something like this:
std::vector<std::string> stringVector = /* get data from somewhere */
std::vector<int> intVector;
std::vector<char> charVector;
for (std::vector<std::string>::const_iterator it = stringVector.begin(); it != stringVector.end(); it++)
{
if (it->length() == 0)
continue; // ignore any empty strings
int intValue;
std::istingstream ss(*it);
if (ss >> someValue) // try to parse string as integer
intVector.push_back(someValue); // int parsed successfully
else
charVector.pushBack((*it)[0]);
}
This assumes anything that cannot be parsed as an integer should be pushed into the char vector instead (so, 234, 100000 and -34 will be put into intVector, and /, + etc will be put into charVector). Only the first character of a non-integer value is pushed, so if you have *hello or *123, only * will be put into the charVector.
If you are using C++11, you can swap the std::vector<std::string>::const_iterator with auto to make it look a bit nicer.