# Manage input values from file according to number of elements per line

I was given the a test file with the following kind of content, an arbitrary number of integer pairs divided by a newline and a final line with one integer:

1 2
3 4
5


I had to use the couples as values for two data members of a series of objects and I had to put the last integer in a separate variable.

I eventually wrote a working code, but the second inner while loop is very wasteful (it is the one loading the last value).

Also, I had to include <fstream>, <sstream> and <string> just to manage this input file.

What is a simpler and more elegant way to solve this problem?

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>

class anObject
{
public:
int one;
int two;
};
int main()
{
std::ifstream inFile;
inFile.open("myFile.txt", std::ios::in);

int myVar=0;
std::string inLine;

while (getline(inFile, inLine))
{
int inputA, inputB;
std::stringstream inStream(inLine);
std::stringstream inStreamAlt(inLine);

while (inStream >> inputA >> inputB)
{
anObject inObj;
inObj.one = inputA;
inObj.two = inputB;
objList.push_back(inObj);
}

while (inStreamAlt >> inputA)
{
myVar = inputA;
}
}
}


You can simplify your loops logic like this

while (getline(inFile, inLine)) {
std::istringstream inStream(inLine);

anObject inObj;
if((inStream >> inObj.one) && (inStream >> inObj.two)) {
objList.push_back(inObj);
}
else {
myVar = inObj.one;
}
}


relying on exactly that form of input you mentioned is given.

std::ios::in is redundant for std::ifstream:

inFile.open("myFile.txt", std::ios::in);
// ^^^^^^^^^^^^^^


also open() isn't explicitely needed. You can simply write:

std::ifstream inFile("myFile.txt");


class anObject
{
public:
int one;
int two;
};


can be simpler written as struct:

struct anObject
{
int one;
int two;
};


This may not apply in your case, but I think it's at least worth considering for a fair number of real-life tasks. The difficulty here is caused primarily by a poorly designed file format. Rather than warping your code to fit that format, if you can, it's better to redesign the format to be easy to work with.

In this case, the difficulty is caused almost entirely by the single number being at the end of the file. It would be much cleaner if that single number were at the beginning instead. If the file were formatted this way, the job would become truly simple and the code (IMO) quite nice:

struct anObject {
int a;
int b;

friend std::istream &operator>>(std::istream &is, anObject &o) {
return is >> o.a >> o.b;
}
};

int main() {
std::ifstream in("myfile.txt");

int myVar;
in >> myVar;

std::vector<anObject> objList { std::istream_iterator<anObject>(in), {} };
}


There are certainly times that file formats are fixed and can't be fixed, no matter how badly they're designed. If this one of those cases, I'd read through πάντα ῥεῖ's fine answer for excellent advice.

If, however, the formatting is basically arbitrary and can actually be changed fairly easily (which I find to be true more often than many expect) it's much better to simplify the problem than deal with a problem that's unnecessarily difficult.

• THX for the flowers ;-) @Jerry. Your answer extrapolates the problem into the right direction +1. Well, student tasks or legacy stuff often are what they just are. But certainly I won't use the code I proposed here for real life production code. – πάντα ῥεῖ Mar 28 '17 at 22:24
• This specific case was an homework wich has already been corrected, but for other real life tasks I would certainly look at this answer. – maja Mar 29 '17 at 7:02