How to eliminate the "waste" of a stringstream?

0

While trying to resolve this issue with this answer I found myself with the problem that I can not eliminate the "residuals" that remain after using stringstream and I wanted to ask them if they can advise me on how to eliminate the garbage that remains.

The remainder that remains is the -1.23 of the second line which bothers, since the third line contains nothing and the last data is loaded which is the -1.23

  

Note: I'm using the compiler called Code :: Blocks, version: 16.01

    
asked by bassily 04.11.2016 в 00:44
source

1 answer

4

Your problem is in the condition of% internal while . When you read the last number of a line, for example, your -1.23 , the flow stops just behind the -1.23 , without finding eof , and therefore !ss.eof() == true , entering the loop of new.

And with the empty line equal: if you have not yet started reading !ss.eof() == true , and on entering, i == 1 .

Why is b still worth 1.23 ? Because when entering the loop even if there is no data, ss >> b fails (here is when it finds eof ), and b is not modified.

The solution is to replace the internal loop of:

while(!ss.eof())

for

while (ss >> b)

In saying, what interests you is to know if the reading ss >> b could be completed. Anyway, you have more errors ( a should be float and there could be numbers less than -10000 ), besides the fact that double s are normally more efficient than float s [†] .

Here the improved version:

#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>

using namespace std;

int main()
{
    ifstream f("mayores.txt");
    string in;

    while(getline(f, in)) { // Misma razón que con 'ss'.
       int i = 0, j;
       double a = std::numeric_limits<double>::min(), b;

       istringstream ss(in);

       while(ss >> b){
            ++i; // <pedantic_mode>: ++i es más eficiente que i++.

            if(b > a){
                a = b;
                j = i;
            }
        }

        if(i == 0) j = -1;

        cout << j << endl;
    }
}

Or, short version (although not more efficient), with iterators, that I love:

#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>
#include <iterator>
#include <algorithm>
#include <vector>
#include <string>

using namespace std;

int main()
{
    ifstream f("mayores.txt");
    string in;
    vector<double> line_values; // [†2]

    while(getline(f, in)) {
       line_values.clear();
       istringstream ss(in);

       copy(istream_iterator<double>(ss), istream_iterator<double>(),
            back_inserter(line_values));

       auto it = max_element(line_values.begin(), line_values.end());
       cout << distance(line_values.begin(), it) - 1 << endl; // [†3]
    }
}

[†]: Efficiency float vs. double depends on the architecture. If the floating point unit of the processor is implemented to deal with float s, the double s are slower because you have to transform the values returned by the processor ( float ) to the target type ( double ). And vice versa. As it turns out, most modern processors work natively with double s.

[† 2]: Vectors reserve memory as they grow, and clear() does not release previously reserved memory, so you do not have to rebook it. That is, the memory currently reserved by the vector ( capacity() ) is always greater than or equal to its current size ( size() ). That is why I declare the vector out of the loop, to take advantage of the capacity() acquired in previous laps of the loop.

[† 3]: max_element() returns an iterator to the largest element. If the vector is empty, max_element(v.begin(), v.end()) == v.end() , and std::distance return 0.

NOTE: For the curious, here is a version with iterators that only goes through the sequence of values once:

#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>
#include <iterator>
#include <algorithm>
#include <string>

using namespace std;
using double_reader = std::istream_iterator<double>;

int main()
{
    istringstream f("mayores.txt");
    string in;

    while(getline(f, in)) {
        istringstream ss(in);

        int pos = -1, max_pos = -1;
        double max = std::numeric_limits<double>::min();

        for_each(double_reader(ss), double_reader(), [&](const double& d) {
            ++pos;

            if (d > max) {
                max = d;
                max_pos = pos;
            }
        });

       cout << max_pos << std::endl;
    }
}
    
answered by 04.11.2016 / 03:17
source