0

I have a code, with that I can show the out put on the screen. But, I want to put the output in a text file. Frankly, I read about the Lambda expression, but it is hard for me to understand its function (as I am beginner).

#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
#include <vector>
using Matrix = std::vector<std::vector<float>>;

void addRow(Matrix& M, const int rowNum, const int id, const float type, const float x, const float y,const float z) {
    M[rowNum][0] = id;
    M[rowNum][1] = type;
    M[rowNum][2] = x;
    M[rowNum][3] = y;
    M[rowNum][4] = z;
}

int main() {
    string line;
    float x0, y0, z0, x1, y1, z1, type;
    int NUMBER_line=0, id=0,NUMBER_line1=0,NUMBER_line3=0;

    ofstream secondoutput;                  // the output text file
    secondoutput.open ("secondoutput.txt"); // the output text file

    ifstream myfile("1.lammpstrj");
    string namefile;
    if (myfile.is_open()) {
        for (int lineno = 0; getline(myfile, line) && lineno < 7; lineno++) {
            if (lineno == 2)  myfile >> NUMBER_line;
        }
        cout << " NUMBER_line: " << NUMBER_line << endl;

        Matrix Input0(NUMBER_line, std::vector<float>(5));
        for (float linenoq = 0; getline(myfile, line) && linenoq < NUMBER_line; linenoq++) {
            myfile >> id >> type >> x0 >> y0 >> z0;
            addRow(Input0, linenoq, id, type, x0, y0, z0);

        }


        for (int i=0; i <3; i++){
            for (int lineno = 0; getline(myfile, line) && lineno < 7; lineno++) {
                if (lineno == 2)  myfile >> NUMBER_line1;
            }


            Matrix Input1(NUMBER_line1, std::vector<float>(5));
            for (int linenoq = 0; getline(myfile, line) && linenoq < NUMBER_line1; linenoq++) {
                myfile >> id >> type >> x1 >> y1 >> z1;
                addRow(Input1, linenoq, id, type, x1, y1, z1);

            }

            Matrix Output(NUMBER_line, std::vector<float>(5));
            for (size_t row = 0; row < Output.size(); ++row) {
                for (size_t col = 0; col < Output[0].size(); ++col) {
                    if (col < 2) {
                        Output[row][col] = Input0[row][col];
                    }
                    else {
                        Output[row][col] = Input1[row][col] - Input0[row][col] ;
                    }
                }
            }

            std::for_each(Output.cbegin(), Output.cend(),
            [](auto const& row) {
                std::for_each(row.cbegin(), row.cend(),
                    [](const float value) { 
                        cout << value << " "; 
                        secondoutput << value << " "; // the output text file
                        });
                cout << endl;
                secondoutput << "\n" ; // the output text file

            });
        }
        secondoutput.close();
    }
    else cout << "Unable to open file";
    return 0;
}

Could I ask to help me? I want to have a output text file like what the output writes on the screen. It seems the most important matters are about the the place where I put the "secondoutput << value << " ";" and "secondoutput << "\n" ;".

I don't know where they should be. I always put "secondoutput << value << " ";" in other codes, and they work well, and give me an output text file. But now, I don't know why they don't work. Thanks in advance for any help

regards

max66
  • 65,235
  • 10
  • 71
  • 111
  • 1
    I will never understand why anyone would use `for_each` instead of ranged for loops in such a situation. Instead of `for_each` and the lambda expressions, you could write `for(const auto& row : Output) {for(const auto& value) {cout...; secondoutput...}}` – eike Nov 12 '19 at 18:27
  • @eike are you mine if i substitute these with for_each, then the code can create a text file and put the output in it? –  Nov 12 '19 at 18:55

1 Answers1

1

I want to have a output text file like what the output writes on the screen.

It's difficult help you without the content of an input file, anyway...

In your code there is a problem; in your lambdas

        [](auto const& row) {
            std::for_each(row.cbegin(), row.cend(),
                [](const float value) { 
                    cout << value << " "; 
                    secondoutput << value << " "; // the output text file
                    });
            cout << endl;
            secondoutput << "\n" ; // the output text file
        }

you're using secondoutput without capturing it.

To solve this problem, you can add & in the capture list of both lambdas

 // .....V  add &
        [&](auto const& row) {
            std::for_each(row.cbegin(), row.cend(),
                [&](const float value) { 
 /*   add & .....^ */ cout << value << " "; 
                    secondoutput << value << " "; // the output text file
                    });
            cout << endl;
            secondoutput << "\n" ; // the output text file
        }

so you can capture everything (also secondoutput) by reference.

Bonus Unrequested Suggestion: observe that, as suggested by eike, you can avoid capturing, lambdas and std::for_each() simply using ranged for loops (with an additional eike's suggestion to avoid multiple flushes)

        for ( auto const & row : Output )
         {
           for ( auto const & value : row )
            {
              std::cout << value << ' ';
              secondoutput << value << ' ';
            }

           std::cout << '\n';
           secondoutput << '\n';
         }

       std::cout << std::flush; // you can avoid it, because you're ending the program
       secondoutput << std::flush; // you can avoid it, because you're closing the file
max66
  • 65,235
  • 10
  • 71
  • 111
  • 1
    I strongly suggest not to use `std::endl` for line breaks, because that includes a flush every time it is used. Just use `'\n'` if you are not in an unstable environment, where you need to get the full output before the program crashes. Standard streams flush on destruction. – eike Nov 12 '19 at 18:58
  • @eike - good point: added a single `std::flush` at the end of the external loop; thanks. – max66 Nov 12 '19 at 19:03
  • 1
    Edited my comment a little late there. The streams flush on destruction, so you should not need to explicitly flush at all. – eike Nov 12 '19 at 19:04
  • @eike - another good point; this time I add it as a comment (given I show a fragment of a program... maybe someone can copy it in a more complex code and the `std::flush` could be useful). – max66 Nov 12 '19 at 19:09
  • dear @max66 so many thanks for helping to me. and also what good comments are mentioned by you and "eike" for line breaks –  Nov 12 '19 at 19:24