Linear Data Structure
Linear Data Structure

Reputation: 342

How to do sorting in a text file in c++

I am working on my C++ (File Handling) Project but got stuck on a point

Here is my .txt file

SNO, Name, NoOfPeopleLiked
1, The Shawshank Redemption, 77 
2, The Godfather, 20        
3, Into The Wild, 35
4, The Dark Knight, 55      
5, 12 Angry Men, 44
6, Schindler's List, 33
7, The Lord of the Rings: The Return of the King, 25
8, Pulp Fiction, 23
9, The Good, the Bad and the Ugly, 32   
10, The Lord of the Rings: The Fellowship of the Ring, 56

I have to display the top 5 movies with respect to NoOfPeopleLiked Just like that:

Sample Output

1, The Shawshank Redemption, 77
2, The Lord of the Rings: The Fellowship of the Ring, 56
3, The Dark Knight, 55
4, 12 Angry Men, 44
5, Into The Wild, 36

so I have to do sorting and this is what I have done so far


void topFive()
{
    Movies v[20];       //class object array
    fstream top;        //for reading
    top.open("movies.txt");

    for (int h = 0; h < 10; h++) // reading from txt file
    {
        top >> v[h].serial >> v[h].movieName >> v[h].liked; 
    }
    // run loops two times: one for walking throught the array
    // and the other for comparison
    for (int step = 0; step < 5; ++step) 
    {
        for (int i = 0; i < 5 ; ++i) 
        {

            // To sort in descending order, change > to < in this line.
            if (v[i].liked > v[i + 1].liked) 
            {

                // swap if greater is at the rear position
                int temp = v[i].liked;
                v[i].liked = v[i + 1].liked;
                v[i + 1].liked = temp;
            }
        }
    }
    //  to print the array
    for (int i = 0; i < 5; ++i)
    {
        cout << v[i].serial << ", " << v[i].movieName << ", " << v[i].liked << endl;
    }
}   

To be Honest I did not know how to do it perfectly I am stucked with this problem for about 6-7 hours and still can't make any logic. I hope you guyz can help me and guide me better. Thanks in advance :)

Upvotes: 3

Views: 8286

Answers (2)

Arty
Arty

Reputation: 16767

I've implemented next solution using std::regex module. Plus some strings operations. And of cause sorting!

In my code input file is called 0302.txt, please rename it to what you need before running code.

Try it online!

#include <vector>
#include <string>
#include <regex>
#include <fstream>
#include <tuple>
#include <iostream>
#include <stdexcept>
#include <algorithm>

int main() {
    try {
        auto StrTrim = [](std::string & str){
            str.erase(0, str.find_first_not_of("\t\n\v\f\r ")); // left trim
            str.erase(str.find_last_not_of("\t\n\v\f\r ") + 1); // right trim
        };
        std::ifstream ifile("0302.txt");
        std::string line;
        std::vector<std::string> lines;
        // Read all lines of file.
        while (std::getline(ifile, line)) {
            StrTrim(line);
            if (line.empty())
                continue;
            lines.push_back(line);
        }
        if (!lines.empty())
            lines.erase(lines.begin(), lines.begin() + 1); // remove first header line
        lines.erase(lines.begin(), lines.begin() + 1); // remove first header line
        std::vector<std::tuple<size_t, std::string, size_t>> data;
        std::regex re(R"((\d+)\s*,\s*(.+)?\s*,\s*(\d+))");
        for (auto const & line: lines) {
            std::smatch matches;
            if (std::regex_match(line, matches, re)) {
                if (matches.size() != 4)
                    throw std::runtime_error("Matched line with not 3 elements: '" + line + "'!");
                data.push_back(std::make_tuple(size_t(std::stoi(matches[1])), matches[2], size_t(std::stoi(matches[3]))));
            } else
                throw std::runtime_error("Unmatched line: '" + line + "'!");
        }
        std::sort(data.begin(), data.end(), [](auto const & l, auto const & r){
            return std::get<2>(l) > std::get<2>(r);
        });
        for (size_t i = 0; i < 5; ++i) {
            if (i >= data.size())
                break;
            std::cout << (i + 1) << "|" << std::get<0>(data[i]) << ", " << std::get<1>(data[i]) << ", " << std::get<2>(data[i]) << std::endl;
        }
        return 0;
    } catch (std::exception const & ex) {
        std::cout << "Exception: " << ex.what() << std::endl;
        return -1;
    }
}

Input file 0302.txt:

SNO, Name, NoOfPeopleLiked
1, The Shawshank Redemption, 77 
2, The Godfather, 20        
3, Into The Wild, 35
4, The Dark Knight, 55      
5, 12 Angry Men, 44
6, Schindler's List, 33
7, The Lord of the Rings: The Return of the King, 25
8, Pulp Fiction, 23
9, The Good, the Bad and the Ugly, 32   
10, The Lord of the Rings: The Fellowship of the Ring, 56

Console output:

1|1, The Shawshank Redemption, 77
2|10, The Lord of the Rings: The Fellowship of the Ring, 56
3|4, The Dark Knight, 55
4|5, 12 Angry Men, 44
5|3, Into The Wild, 35

Upvotes: 1

Jarvis
Jarvis

Reputation: 8564

You can just insert the strings from the file inside a vector and sort with a custom comparator function. This comparator function can extract the rank from the input string (assuming the rank is after the last comma, assuming the input schema is uniform) and use it in comparison. Code:

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

using namespace std;

int get_rank(std::string input) {
    std::stringstream ss(input);
    std::string s;
    // keep extracting strings, last one would be your 'int' rank
    for(; ss >> s; );
    return std::atoi(s.c_str());
}

int main() {
    std::ifstream infile("movies.txt");
    std::vector<std::string> v;
    std::string line;
    std::getline(infile, line);
    for( ; getline( infile, line ); )
        v.push_back(line);
    std::sort(v.begin(), v.end(), [](std::string s1, std::string s2) -> bool { return get_rank(s1) > get_rank(s2); });
    for(int i = 0;i < 5;i++)
        cout << i + 1 << "," << v[i].substr(v[i].find(",") + 1) << endl;
    return 0;
}

Upvotes: 2

Related Questions