Because of spaces and different length of data in each line, the lexicographic sorting of lines as strings may produce unexpected results or be totally wrong.
Therefore I would recommend to split the lines into it 4 parts, which is very simple using normal IO-extract-functionality using the >> operator.
The data of one row can be stored in a struct. That is somehow intuitive, readable and understandable. For storing the whole list, we can use a std::vector of such a struct.
Instead of using a struct, we can also use a std::tuple as proposed by Jarod42. A std::tuple has comparison operators, which allow ultra simple sorting of one row later.
Anyway. Let us start with a struct, which has additional possibilities, as shown later.
- Define the struct
- Open the file and check, if it could be opened
- Define a
std::vector of the above struct
- Create a temporary instance of a struct, te be able to read data into it
- In a loop, extract data from the file and store in struct-elements
- Push back each just read data into the
vector (we will call it database)
- Sort with a lambda expression to have full control on how things will be sorted
- Show result to the user
This can be coded in many ways. Look at on potential example below:
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iomanip>
struct Data {
int i1{};
int i2{};
double d1{};
double d2{};
};
int main() {
// Open the source textfile and check, if it could be opened
std::ifstream textfile("Limit.txt");
if (textfile) {
// Here we will store all data
std::vector<Data> database{};
// Temporary storage for 1 line
Data data{};
// Read all lines and add data to the database
while (textfile >> data.i1 >> data.i2 >> data.d1 >> data.d2)
database.push_back(data);
// Sort database and use a lambda to do it as wished
std::sort(database.begin(), database.end(), [](const Data& d1, const Data& d2) {
return d1.i1 == d2.i1 ? (d1.i2 == d2.i2 ? (d1.d1 == d2.d1 ? d1.d2 < d2.d1 : d1.d1 < d2.d1) : d1.i2 < d2.i2) : d1.i1 < d2.i1; });
// Debug output
for (const Data& d : database)
std::cout << std::left << std::setw(4) << d.i1 << std::setw(4) << d.i2 << std::setw(12) << d.d1 << d.d2 << '\n';
}
else std::cerr << "\n*** Error! Could not open source file\n\n";
}
But that is not all.
As you know, C++ is an object oriented language. And we can store data together with functions, operating on this data, in a struct (a struct is a class).
So, we can add input and output functions and the less than operator that is needed for sorting.
Then the main function will be significantly simpler.
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iomanip>
struct Data {
int i1{};
int i2{};
double d1{};
double d2{};
// Methods / operators
// Input
friend std::istream& operator >> (std::istream& is, Data& data) {
return is >> data.i1 >> data.i2 >> data.d1 >> data.d2;
}
// Output
friend std::ostream& operator << (std::ostream& os, const Data& d) {
return os << std::left << std::setw(4) << d.i1 << std::setw(4)
<< d.i2 << std::setw(12) << d.d1 << d.d2;
}
// Comparison
bool operator < (const Data& other) {
return i1 == other.i1 ? (i2 == other.i2 ? (d1 == other.d1 ? d2 < other.d1 : d1 < other.d1) : i2 < other.i2) : i1 < other.i1;
}
};
int main() {
// Open the source textfile and check, if it could be opened
std::ifstream textfile("Limit.txt");
if (textfile) {
// Here we will store all data
std::vector<Data> database{};
// Temporary storage for 1 line
Data data{};
// Read all lines and add data to the database
while (textfile >> data)
database.push_back(data);
// Sort database
std::sort(database.begin(), database.end());
// Debug output
for (const Data& d : database)
std::cout << d << '\n';
}
else std::cerr << "\n*** Error! Could not open source file\n\n";
}
Advantage: Understandable and simple. Good control for sorting.
Disadvantage: Complex sorting criteria