I'm trying to read each line from a file and store the data in each line. Say the line is "x y z". What arguments should the getline function use in order to read and store x, y and z individually?
void readData(Gene *data, int num)
{
int codeNum;
int i = 0;
int k = num;
ifstream inputFile;
inputFile.open("example.data");
inputFile >> codeNum;
while(i < k){
getline(inputFile, data[i].geneCode, data[i].MutCode[0],
data[i].MutCost[0], data[i].MutCode[1],
data[i].MutCost[1]);
i++;
}
This is what I have. Note that all the vars I'm trying to read are strings, and that k is the total number of lines. when trying to compile I get an error saying "no matching function to call to getline()" and something about "candidate function template not viable". Any idea what I'm doing wrong?
I highly recommend you use a vector of structures (or classes) rather than multiple, parallel arrays.
struct Mutation_Code_Cost
{
Mutation_Code_Type MutCode;
Mutation_Cost_Type MutCost;
};
struct Gene
{
Gene_Code_Type geneCode;
Mutation_Code_Cost mutation_info[2];
};
You can then overload operator>> to read in the structures from a text stream:
struct Mutation_Code_Cost
{
Mutation_Code_Type MutCode;
Mutation_Cost_Type MutCost;
friend std::istream& operator>>(std::istream& input, Mutation_Code_Cost& mcc);
};
std::istream& operator>>(std::istream& input, Mutation_Code_Cost& mcc)
{
input >> mcc.MutCode;
input >> mcc.MutCost;
return input;
}
struct Gene
{
Gene_Code_Type geneCode;
Mutation_Code_Cost mutation_info[2];
friend std::istream& operator>>(std::istream& input, Gene& g);
};
std::istream& operator>>(std::istream& input, Gene& g)
{
input >> g.geneCode;
input >> g.mutation_info[0];
input >> g.mutation_info[1];
return input;
}
You can the read from the file like so:
std::vector<Gene> database;
Gene g;
std::string record;
while (std::getline(input_file, record))
{
std::istringstream record_stream(record);
if (record >> g)
{
database.push_back(g);
}
}
Related
I have an input from isstream
1 2
3 4
5 6
I would like to populate this from isstream overloading the >> operator
the input would be something like
Matrix m;
string input = "1 2 \n 3 4\n 5 6\n";
istringstream ss(input);
ss >> m;
how do I implement the >> operator to parse the matrix from isstream?
I have tried the code below but the peek call seems to ignoring the new line
std::istream& operator>>(std::istream& is, Matrix& s)
{
vector<vector<int>> elements;
int n;
while (!is.eof())
{
vector<int> row;
while ((is.peek() != '\n') && (is >> n))
{
row.push_back(n);
}
is.ignore(numeric_limits<streamsize>::max(), '\n');
elements.push_back(row);
}
return is;
}
The simplest way is to parse one line at a time:
std::istream& operator>>(std::istream& is, Matrix& s)
{
std::vector<std::vector<int>> elements;
for (std::string line; std::getline(is, line);) {
std::istringstream line_iss{line};
std::vector<int> row(std::istream_iterator<int>{line_iss},
std::istream_iterator<int>{});
elements.push_back(std::move(row));
}
s.set(elements); // dump elements into s (adapt according to the interface of Matrix)
return is;
}
So, I need to store the data from the text file into 2d array. I tried using vectors. So here is the sample data from the text file:
START 13
PID 11
CORE 120
SSD 0
CORE 60
SSD 0
CORE 20
SSD 0
I want to store this data as final_vec[x][y]. This is what I tried:
void read_file(const string &fname) {
ifstream in_file(fname);
string line;
vector<string> temp_vec;
vector<vector<string>> final_vec;
while ( getline (in_file,line) )
{
stringstream ss(line);
string value;
while(ss >> value)
{
temp_vec.push_back(value);
}
final_vec.push_back(temp_vec);
}
for (int i = 0; i < final_vec.size(); i++) {
for (int j = 0; j < final_vec[i].size(); j++)
cout << final_vec[i][j] << " ";
cout << endl;
}
}
int main()
{
read_file("test.txt");
return 0;
}
I get error:
main.cpp: In function ‘void read_file(const string&)’:
main.cpp:29:29: error: variable ‘std::stringstream ss’ has initializer but incomplete type
stringstream ss(line);
I am not sure if I am on the right track.
IMHO, a better solution is to model each line as a record, with a struct or class:
struct Record
{
std::string label;
int number;
friend std::istream& operator>>(std::istream& input, Record& r);
};
std::istream& operator>>(std::istream& input, Record& r)
{
input >> r.label;
input >> r.number;
return input;
}
The overloaded operator>> makes the input loop a lot simpler:
std::vector<Record> database;
Record r;
while (infile >> r)
{
database.push_back(r);
}
Rather than have a 2d vector of two different types, the above code uses a 1D vector of structures.
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);
}
I have an array of dvd from a Video class I created
Video dvd[10];
each video has the property,
class Video {
string _title;
string _genre;
int _available;
int _holds;
public:
Video(string title, string genre, int available, int holds);
Video();
void print();
void read(istream & is, Video dvd);
int holds();
void restock(int num);
string getTitle();
~Video();
};
I'm trying to fill up this array with data from my text file where each info such as the title and genre is separated by a comma
Legend of the seeker, Fantasy/Adventure, 3, 2
Mindy Project, Comedy, 10, 3
Orange is the new black, Drama/Comedy, 10, 9
I've tried using getline(in, line, ',') but my brain halts when its time to insert each line into the dvd array.
I also created a read method to read each word separated by a whitespace but I figured thats not what I really want.
I also tried to read a line with getline, store the line in a string and split it from there but I get confused along the line.
**I can get the strings I need from each line, my confusion is in how to insert it into my class array in the while loop especially when I can only read one word at a time.
I need help on what approach I should follow to tackle this problem.
**My code
#include <iostream>
#include <fstream>
#include <cassert>
#include <vector>
#define MAX 10
using namespace std;
class Video {
string _title;
string _genre;
int _available;
int _holds;
public:
Video(string title, string genre, int available, int holds);
Video();
void print();
void read(istream & is, Video dvd);
int holds();
void restock(int num);
string getTitle();
~Video();
};
Video::Video(string title, string genre, int available, int holds){
_title = title;
_genre = genre;
_available = available;
_holds = holds;
}
void Video::read (istream & is, Video dvd)
{
is >> _title >> _genre >> _available>>_holds;
dvd = Video(_title,_genre,_available,_holds);
}
int Video::holds(){
return _holds;
}
void Video::restock(int num){
_available += 5;
}
string Video::getTitle(){
return _title;
}
Video::Video(){
}
void Video::print(){
cout<<"Video title: " <<_title<<"\n"<<
"Genre: "<<_genre<<"\n"<<
"Available: " <<_available<<"\n"<<
"Holds: " <<_holds<<endl;
}
Video::~Video(){
cout<<"DESTRUCTOR ACTIVATED"<<endl;
}
int main(int params, char **argv){
string line;
int index = 0;
vector<string> tokens;
//Video dvd = Video("23 Jump Street", "comedy", 10, 3);
//dvd.print();
Video dvd[MAX];
dvd[0].holds();
ifstream in("input.txt");
/*while (getline(in, line, ',')) {
tokens.push_back(line);
}
for (int i = 0; i < 40; ++i)
{
cout<<tokens[i]<<endl;
}*/
if(!in.fail()){
while (getline(in, line)) {
dvd[index].read(in, dvd[index]);
/*cout<<line<<endl;
token = line;
while (getline(line, token, ',')){
}
cout<<"LINE CUT#####"<<endl;
cout<<line<<endl;
cout<<"TOKEN CUT#####"<<endl;*/
//dvd[index] =
index++;
}
}else{
cout<<"Invalid file"<<endl;
}
for (int i = 0; i < MAX; ++i)
{
dvd[i].print();
}
}
First, I would change the Video::read function into an overload of operator >>. This will allow the Video class to be used as simply as any other type when an input stream is being used.
Also, the way you implemented read as a non-static member function returning a void is not intuitive and very clunky to use. How would you write the loop, and at the same time detect that you've reached the end of file (imagine if there are only 3 items to read -- how would you know to not try to read a fourth item)? The better, intuitive, and frankly, de-facto way to do this in C++ is to overload the >> operator.
(At the end, I show how to write a read function that uses the overloaded >>)
class Video
{
//...
public:
friend std::istream& operator >> (std::istream& is, Video& vid);
//..
};
I won't go over why this should be a friend function, as that can be easily researched here on how to overload >>.
So we need to implement this function. Here is an implementation that reads in a single line, and copies the information to the passed-in vid:
std::istream& operator >> (std::istream& is, Video& vid)
{
std::string line;
std::string theTitle, theGenre, theAvail, theHolds;
// First, we read the entire line
if (std::getline(is, line))
{
// Now we copy the line into a string stream and break
// down the individual items
std::istringstream iss(line);
// first item is the title, genre, available, and holds
std::getline(iss, theTitle, ',');
std::getline(iss, theGenre, ',');
std::getline(iss, theAvail, ',');
std::getline(iss, theHolds, ',');
// now we can create a Video and copy it to vid
vid = Video(theTitle, theGenre,
std::stoi(theAvail), // need to change to integer
std::stoi(theHolds)); // same here
}
return is; // return the input stream
}
Note how vid is a reference parameter, not passed by value. Your read function, if you were to keep it, would need to make the same change.
What we did above is that we read the entire line in first using the "outer" call to std::getline. Once we have the line as a string, we break down that string by using an std::istringstream and delimiting each item on the comma using an "inner" set of getline calls that works on the istringstream. Then we simply create a temporary Video from the information we retrieved from the istringstream and copy it to vid.
Here is a main function that now reads into a maximum of 10 items:
int main()
{
Video dvd[10];
int i = 0;
while (i < 10 && std::cin >> dvd[i])
{
dvd[i].print();
++i;
}
}
So if you look at the loop, all we did is 1) make sure we don't go over 10 items, and 2) just use cin >> dvd[i], which looks just like your everyday usage of >> when inputting an item. This is the magic of the overloaded >> for Video.
Here is a live example, using your data.
If you plan to keep the read function, then it would be easier if you changed the return type to bool that returns true if the item was read or false otherwise, and just calls the operator >>.
Here is an example:
bool Video::read(std::istream & is, Video& dvd)
{
if (is.good())
{
is >> dvd;
return true;
}
return false;
}
And here is the main function:
int main()
{
Video dvd[10];
int i = 0;
while (i < 10 && dvd[i].read(std::cin, dvd[i]))
{
dvd[i].print();
++i;
}
}
Live Example #2
However, I still say that the making of Video::read a non-static member makes the code in main clunky.
I am reading the data with different variables by the following codes, currently when the program touches missing values (represented in data by string "NA", it will change them to zero. Alternatively, I wonder if how can we remove entire rows when program touch "NA". I have tried to look for the same question but they all are for R, not C++. Please, if you can give me some advises. Thanks
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
struct Data {
vector<double> cow_id;
vector<double> age_obs;
vector<double> dim_obs;
vector<double> my_obs;
vector<double> mcf_obs;
vector<double> mcp_obs;
vector<double> mcl_obs;
vector<double> bw_obs;
vector<double> bcs_obs;
double get_number (string value)
{
if (value == "NA")
{return 0.0;}
else
{
istringstream iss (value);
double val;
iss>>val;
return val;
}
}
void read_input (const string filepath)
{
ifstream data_in (filepath.c_str());
if (!data_in)
{cout<<"Failed to open"<<endl;}
else
{
// Read tokens as strings.
string id, age, dim, my, mcf, mcp, mcl, bw, bcs;
string dummy_line;
getline(data_in, dummy_line);
string line;
while (data_in >> id >> age >> dim >> my >> mcf >> mcp >> mcl >> bw >> bcs)
{
// Get the number from the string and add to the vectors.
cow_id.push_back(get_number(id));
age_obs.push_back(get_number(age));
dim_obs.push_back(get_number(dim));
my_obs.push_back(get_number(my));
mcf_obs.push_back(get_number(mcf));
mcp_obs.push_back(get_number(mcp));
mcl_obs.push_back(get_number(mcl));
bw_obs.push_back(get_number(bw));
bcs_obs.push_back(get_number(bcs));
}
data_in.close();
}
size_t size=age_obs.size();
for (size_t i=0; i<size; i++)
{
cout<<cow_id[i]<<'\t'<<age_obs[i]<<'\t'<<dim_obs[i]<<'\t'<<my_obs[i] <<'\t'<<mcf_obs[i]<<'\t'<<mcp_obs[i]<<'\t'<<mcl_obs[i]<<'\t'<<bw_obs[i] <<'\t'<<bcs_obs[i]<<endl;
}
};
int main()
{
Data input;
input.read_input("C:\\Data\\C++\\learncpp\\data.txt");
}
Let's talk tables here.
Tables are containers of records (rows). The data you are capturing from your input file is already organized into records. So the obvious model is to use a structure that matches your file's data records.
struct Record
{
unsigned int cow_id;
unsigned int age_obs;
unsigned int dim_obs;
// ...
};
Your table could be represented as:
std::vector<record> my_table;
So to remove a record from the table, you can use the std::vector::erase() method. Easy. Also, you can use the std::find() function to search the table.
Let's relieve some reader's headaches with your present code by introducing a concept of the record loading its members from the file.
Reading a record from a file is best performed by overloading the stream extraction operator>>:
struct Record
{
//...
friend std::istream& operator>>(std::istream& input, Record& r);
};
std::istream&
operator>>(std::istream& input, Record& r)
{
std::string record_text;
std::getline(input, record_text);
// Extract a field from the record text and check for NA,
// Assign fields of r to those values:
r.cow_id = value;
// Etc.
return input;
}
With the overloaded operator, your input looks like:
Record r;
while (input_file >> r)
{
table.push_back(r);
}
Elegant and simple (reducing injection of defects).