Click here to Skip to main content
15,892,927 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have an input like this :
STEP
10
NUMBER line
2
cc
aa
ab
ac
ad
1 1 81 91 101
2 1 82 92 102
STEP
20
NUMBER line
2
cc
aa
ab
ac
ad
1 1 51 61 71
2 1 52 62 72
STEP
30
NUMBER line
2
cc
aa
ab
ac
ad
1 1 51 61 71
2 1 52 62 72

and I have a piece of code like this :
C++
#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;

    ifstream myfile("1.txt");
    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 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 << " "; });

                cout << endl;
            });
    }
    else cout << "Unable to open file";
    return 0;
}

this code subtracts the three last numbers on the lines 21 and 22 from 10 and 11 of my input file, i.e. 51 and 81 or 72 and 102. this code just considers two first "STEP"( for example the first "STEP" stars from line 1 to the end of line 10). Now, how can code be modified, so that code subtracts the numbers of 2nd,3rd,... "STEP" from the first "STEP".(I have more that 1000 STEP)

What I have tried:

If I want to do this subtraction, I have to add this piece of code at the end of code and repeat it for other "STEP", but it is obvious, not being a plausible way:
C++
for (int lineno = 0; getline(myfile, line) && lineno < 7; lineno++) {
    if (lineno == 2)  myfile >> NUMBER_line3;
}
        Matrix Input2(NUMBER_line3, std::vector<float>(5));
for (int linenoq = 0; getline(myfile, line) && linenoq < NUMBER_line3; linenoq++) {
    myfile >> id >> type >> x1 >> y1 >> z1;
    addRow(Input2, linenoq, id, type, x1, y1, z1);
}

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

std::for_each(Output2.cbegin(), Output2.cend(),
 [](auto const& row) {
     std::for_each(row.cbegin(), row.cend(),
         [](const float value) { cout << value << " "; });

     cout << endl;
 });


Now, How can I prevent this addition, by put a loop? thanks in advance for any hint or help
Posted
Updated 11-Nov-19 4:31am

1 solution

I can see why you're having trouble. Both your data structure and the structure of your code is hellbent on working it's way through the task at hand. But as a result, both are inflexible and difficult to adjust.

You should start by breaking up your code into separate functions, and your data into substructures that are suitable to pass around with these functions:

1. Create a struct to hold the data for one STEP block. For now, your code only uses the two rows of numbers, but maybe that is subject to change: what are all the other lines for? For the rows of numbers, you've used a nested vector, but the inner vector is always the same size, so you should use std::array instead:
C++
struct Step {
    std::vector<std::array<int,5>> rows;
};


2. Adjust your addRow() function: currently it doesn't add a row, it only writes data to a row that already exists. There's nothing wrong with actually adding a row however, so let's do it:
C++
void addRow(Step& M, const int id, const float type, const float x, const float y,const float z) {
    std::array<int,5> columns;
    columns[0] = id;
    columns[1] = type;
    columns[2] = x;
    columns[3] = y;
    columns[4] = z;
    M.rows.push_back(columns);
}
Alternately, I suggest to rename your function appropriately.

3. Extract a function 'ReadStep()' that reads a single STEP block from a given file. It must receive the file that it should read from, and it should return a suitable struct that holds the data. Moreover it must indicate when it fails to read the data, be it because the file is at it's end, or for any other reason. Of course, for that purpose, we can just check whether the returned struct has any rows - which actually makes sense if the rows are really only added when there are any data! This is why I preferred making addRow actually adding the row.

One thing to watch out for in this function is your mix of calls to getline() and cin::operator>>(). That is a dangerous thing to do, because the former always removes the end of line character(s) from the input stream, but the latter isn't guaranteed to do the same!

However, assuming your code worked so far, lets not change it:
C++
Step ReadStep(ifstream& input)
{
    Step result;
    for (int lineno = 0; getline(input, line) && lineno < 7; lineno++) {
        if (lineno == 2)  input >> NUMBER_line;
    }
    // cout << " NUMBER_line: " << NUMBER_line << endl; // not here!

    result.rows.resize(NUMBER_line); // see Step type definition below
    for (float linenoq = 0; getline(myfile, line) && linenoq < NUMBER_line; linenoq++) 
    {
        input >> id >> type >> x0 >> y0 >> z0;
        addRow(result.rows, id, type, x0, y0, z0);
    }
    return result;
}

That last for loop could be improved by verifying that there are actually data to read, and the state of input remains valid. In fact, the entire function could be improved by checking the input state, to make sure we haven't reached its end before attempting to read any data.

4. Once you have that function, ReadStep(), it should be easy enough to call it in a loop, store the data, and process them as needed.

One more suggestion: you could turn the two functions ReadStep and addRow into member functions of the struct Step. But of course you don't need that to fix your code.
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900