Let's say you have std::array<int, SIZE> a, and you have saved each element of a into a file in one line separated by a space. Then you want to read them with a std:istream& is via:
is >> std::skipws >> a[0] >> a[1] >> a[2] >> ... >> a[SIZE-1];
How to write this generically for any value of SIZE. Even though there are other easy ways of doing this, I'm curious how it is done with this particular method.
How to write this generically for any value of SIZE.
There are control structures for repeating an operation a variable number of times: loops.
For example:
is >> std::skipws;
for(auto& el : a) {
is >> el;
}
Related
I was solving a question on hackerrank and came across this problem involving string streams.
https://www.hackerrank.com/challenges/c-tutorial-stringstream/problem
For Extracting data, hackerrank has given an example:
stringstream ss("23,4,56");
char ch;
int a, b, c;
ss >> a >> ch >> b >> ch >> c; // a = 23, b = 4, c = 56
However, when I try to export it to a vector, I have to escape the ',' using:
stringstream ss(str);
vector<int> vect;
int i;
while (ss >> i)
{
vect.push_back(i);
if (ss.peek() == ',')
ss.ignore();
}
Why can't I use the extraction operation to get the required word here? Shouldn't the stream escape the ','(Sorry for the noob-level question)?
operator>> extracts the next delimited token, only so far as characters actually belong to the requested data type. So, when using operator>> to read an int, it will extract only digits, not letters, punctuation, etc. That means a comma following a number has to be read separately.
In the first example:
ss >> a reads the first int in the stream
then >> ch reads the comma after it
then >> b reads the next int
then >> ch reads the comma after it
then >> c reads the next int
In the second example:
ss >> i reads the next int in the stream, breaking the loop if fails or EOF
then ss.peek() checks if a comma exists (since the last int doesn't have one), and if found then ss.ignore() skips past it
goto #1
If you try to use operator>> to read a comma that doesn't exist, it will set the stream's eofbit state and fail the extraction. If you use while (ss >> i >> ch), the while would evaluate as false when the last int is reached. Even though ss >> i would succeed, >> ch would fail, and thus i would not be added to the vector.
In theory, you could replace if (ss.peek() == ',') ss.ignore(); inside the loop with char ch; ss >> ch instead. The end effect would be the same, at least for a string like "23,4,56". But, let's say you were given something like "23 4 56" instead. The first example would fail to handle that correctly, but the second example would handle it just fine when using peek()+ignore(), but not when using ss >> ch.
I think you can use this code to escape the ','
std::string valstr;
while (std::getline(ss, valstr, ','))
{
vect.push_back(std::stoi(valstr));
}
I process some data with data in columns like,
1 -0.004002415458937208 0.0035676328502415523
2 -0.004002415796209478 0.0035676331876702957
....
I am only interested in the last two values. I usually find it convenient to read the values as:
std::ifstream file(file_name);
double a, b;
for (lines) {
// | throwing away the first value by reading it to `a`
file >> a >> a >> b;
store(a, b);
}
I'm not sure how readable this is for others, and it might be thought of as an error when the structure of the data is not known. Could I somehow make it look more explicit that I really want to throw away the first read value?
I wanted something in the line of this, but nothing worked:
file >> double() >> a >> b; // I hoped I could create some r-value kind of thing and discard the data in there
file >> NULL >> a >> b;
If you don't want to create a variable explicitly to be ignored, and you feel explicitly ignoring the value with calls to manipulate the stream are too verbose, you could take advantage of the operator>> overload for std::istream that takes a std::istream&(*)(std::istream&) function pointer:
template <typename CharT>
std::basic_istream<CharT>& ignore(std::basic_istream<CharT>& in){
std::string ignoredValue;
return in >> ignoredValue;
}
to be used like:
std::cin >> ignore >> a >> b;
and if you wanted to verify that it was of a form that could be read into a type you could supply an additional template argument specifying the type of ignored value:
// default arguments to allow use of ignore without explicit type
template <typename T = std::string, typename CharT = char>
std::basic_istream<CharT>& ignore(std::basic_istream<CharT>& in){
T ignoredValue;
return in >> ignoredValue;
}
to be used like:
std::cin >> ignore >> a >> b;
// and
std::cin >> ignore<int> >> a >> b;
demo on coliru
You can use std::istream::ignore.
E.g.:
file.ignore(std::numeric_limits<std::streamsize>::max(), ' '); //columns are separated with space so passing it as the delimiter.
file >> a >> b;
You can use file::ignore(255, ' ') to ignore characters until the next space.
std::ifstream file(file_name);
double a, b;
for (lines) {
// skip first value until space
file.ignore(255, ' ');
file >> a >> b;
store(a, b);
}
or you can use an auxiliary variable to store the first value:
std::ifstream file(file_name);
double aux, a, b;
for (lines) {
// skip first value
file >> aux >> a >> b;
store(a, b);
}
I have a task where I expect random input of chars or ints. Is there any way I can understand what is coming next and say cin >> int, or cin >> char. I want to do it with the istream operator >>, because they told us not to do it with a parser. To be precise, I expect an input of a prefix expression. So I don't know when to read an operator, when to read a number. If you have any suggestions I'd appreciate them :)
You can do, without a parser:
int n;
cin >> n;
if (cin.good())
{
// manage integer
}
else
{
char c;
cin.clear();
cin >> c;
// manage character
}
I have an assignment to create a record management system for a class project. When adding records I would like to first read into a vector the contents of my record file currently then perform additions to the file finally outputting back to the record file. However, I'm having a hard time wrapping my mind around how to structure this. I am currently using a dynamic array to store the data but when I try to put it into the vector I it won't let me because it's a pointer. I feel like I'm approaching this entirely wrong and could use some assistance. Here is my input function:
void student::input(istream& inF, student* stud, vector<student>& vect, int size)
{
//local variables
string first, middle, last, addressNum, addressStreet,
phone, gender, email, emContactFirst, emContactLast;
int ID, age;
string ph, emPhone;
while (inF)
{
for (int index = 0; index < size; index++){
inF >> first >> last >> middle;
stud->setName(first, last, middle);
inF >> ID;
stud->setId(ID);
inF >> age;
stud->setAge(age);
inF >> phone;
stud->setPhone(phone);
inF >> addressNum >> addressStreet;
stud->setAddress(addressNum, addressStreet);
inF >> gender;
stud->setGender(gender);
inF >> email;
stud->setEmail(email);
inF >> emPhone;
stud->setEmPhone(emPhone);
inF >> emContactFirst >> emContactLast;
stud->setEmContact(emContactFirst, emContactLast);
inF >> stud->gpa >> stud->hobbies >> stud->major
>> stud->probation;
if (inF.eof())
break;
else
stud++;
vect.push_back(stud);
}
}
}
Problems I see:
You are using while (inF) to break the loop. See Why is iostream::eof inside a loop condition considered wrong?.
You are using one pointer, stud to read all the values and storing the same pointer multiple times in vect. First of all, the compiler should produce an error. You cannot add a pointer to a vector of objects.
It's not clear why the function needs stud as an argument. You can just as easily use a local object in the function. Like this:
for (int index = 0; index < size; index++){
student stud;
if ( !(inF >> first >> last >> middle) )
{
// Deal with error.
}
stud.setName(first, last, middle);
...
}
It's better to check whether the calls to inF >> ... assigned anything successfully and not assume that it succeeded. Instead of:
inF >> first >> last >> middle;
use
if ( !(inF >> first >> last >> middle) )
{
// Deal with error.
}
I suggest changing all such calls.
I have a data file with a lot of columns of doubles but I want to read only two of them with a while loop
double x, y;
ifstream in;
double foo;
while( in >> foo ) {
in >> foo;
in >> foo;
...
in >> x;
in >> y;
... something with x and y
}
Two questions
1) There is a way to do the same thing without a fake double foo?
2) there is a way to do that without repeat in >> foo (or a for loop) like stream to the n° whitespace with a one-line code? There is a built-in function to skip to the n° whitespace?
What I would suggest instead is to read an entire row in a string and use a stringstream to manipulate it or just use something like find_last_of functions from the string class itself to pick out the last two columns and then convert it back to a double.