2

I have to read from a .txt file and out it with a different .txt file. I have to use insertion sort in order to sort them based on two numbers. I could only get this far, I don't know how to do insertion sort in this program where I have two numbers to sort to.

Here is my code:

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main(void)
{
    int serialno[100], suratno[100], ayatno[100];
    string order;

    string str;
    char ch;
    int i = 0;
    int j, temp;

    ifstream fin;
    fin.open("text.txt");

    if(!fin)
    {
        cout << "Cannot open file \'text.txt\'! Quitting.\n";
        exit(0);
    }

    while(fin)
    {

        fin.get(ch); //gets .

        getline(fin, order, '('); //allegedly it removes the delimiter char from stream too

        fin >> suratno;
        fin.get(ch); //gets :
        fin >> ayatno;
        fin.get(ch); //gets )
        fin.get(ch); //gets \n

        cout << serialno << "." << order << "("<<suratno<<":<<ayatno<<")\n";
    }

    fin.close();

    //sort algorithm            
    for (int i = 0; i < length; i++){
        j = i;

        while (j > 0 && suratno [j] < suratno [j-1]){
              temp = suratno [j];
              suratno [j] = suratno [j-1];
              suratno [j-1] = temp;
              j--;
              cout << serialno << endl;
              }
        }
    }

    ofstream fout;
    fout.open("newtext.txt");

    if(!fout)
    {
        cout << "Cannot open output file\'orderedquranorders.txt\'!Quitting.\n";
        exit(0);
    }

    i = 0;
    //write sorted list to output file

    fout.close();

    cout << i << " orders successfully sorted and written.\n";
}

this is the text file (numbers in bracket should be used, firstly with number before colon, and secondly with number after colon):

1. Do not be rude in speech (3:159) 
2. Restrain Anger (3:134)
3. Be good to others (4:36)
4. Do not be arrogant (7:13)
5. Forgive others for their mistakes (7:199)
6. Speak to people mildly (20:44)
7. Lower your voice (31:19)
8. Do not ridicule others (49:11)
9. Be dutiful to parents(17:23)

current output:

  1. Do not be rude in speech (3:159)
  2. Restrain Anger (3:134)
  3. Be good to others (4:36)
  4. Be dutiful to parents(17:23)

expected output:

  1. Restrain Anger (3:134)
  2. Do not be rude in speech (3:159)
  3. Be good to others (4:36)
  4. Be dutiful to parents(17:23)

sorted in terms of both the numbers and the serial no stays the same

Fahad Khalid
  • 21
  • 1
  • 4
  • Go read the help centre on "how to ask a good question". Also read [How to debug small programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) by Eric Lippert. You currently have one huge main function. At the very least split that into three functions: read the input, sort the data, write the output. You can then test "read the input" and "write the output" before starting to test the sort. – Martin Bonner supports Monica Nov 29 '16 at 12:46
  • @MartinBonner i have a txt file i have to read from and it requires sorting. example of data present in my txt file is 1. Do not be rude in speech (3:159) "these numbers in brackets" 2. Restrain Anger (3:134) 3. Be good to others (4:36) – Fahad Khalid Nov 29 '16 at 12:50
  • @YSC any suggestions? – Fahad Khalid Nov 29 '16 at 12:53
  • @FahadKhalid: clearly describe what your program take in input, what it should output, your code and the current output you get. All in the question ([edit] it). Then, ask something as simple as "what did I done wrong?" – YSC Nov 29 '16 at 12:57
  • @YSC it takes the input from a text file which has numbers like(3:159) in it. it sorts them and then output the sorted list to another txt file – Fahad Khalid Nov 29 '16 at 13:00
  • Ok, now what's the expected output for the example you gave, and what is the actual output you get from your implementation? (add them to your question) – YSC Nov 29 '16 at 13:04
  • @YSC thank you for the tip, i updated my Question i hope you ll be able to understand it better this time. – Fahad Khalid Nov 29 '16 at 13:21
  • @MartinBonner can you help me ?? – Fahad Khalid Nov 29 '16 at 13:39
  • Almost. I don't get why entries 4 to 8 shouldn't be in the ouput. You not only to sort them, but to filter it, don't you? – YSC Nov 29 '16 at 13:49
  • @YSC extactly i a have to filter them or we can say manipulate them in such a way that both the numbers in the brackets are in ascending order. Yes and entries 4-8 should be in the output. I just didnt write them in the question. – Fahad Khalid Nov 29 '16 at 14:01
  • Sorry, we can't guess that sort of thing. You need to [edit] the question to include the *full* expected and actual output. (Please reduce the input file as much as possible while still keeping the unexpected output - this may mean deleting lines in the middle.) – Martin Bonner supports Monica Nov 29 '16 at 14:24
  • 1
    I can't even see how this compiles for you. It's not valid C++. For example, `for (int i = 0; i < length; i++){` You never define `length` though. This code plain doesn't run. You are also missing an double quote. – Cinder Biscuits Nov 29 '16 at 15:12

2 Answers2

0

In order to compare two pair of numbers, you can make comparisons like:

 if(suratno[i] < suratno[i-1] || (suratno[i] == suratno[i-1] && ayatno[i] < ayatno[i-1])){
    /* swap */
 }

Or you can use one expression: expr = suratno * 10000 + ayatno. And make just one comparison:

 if(expr[i] < expr[i-1]){
    /* swap */
 }

Also, I have a few observations about your algorithm/code:

  • Don't use using namespace std. Specially in big programs, because it can cause obscure bugs (see an example here). Instead use using std::<name> when you want to avoid std::. Ex. using std::string. In general, avoid using namespace xxxx.
  • I see you did parse the input lines manually, I prefer to use regular expressions, that are much more versatile and powerful, but requires a little learning.
  • When it's necessary to write an error message, always write to stderr stream cerr in C++.
  • In the sort algorithm, it's better start in 1 than 0, because the first item doesn't have a previous item to compare with.
  • Finally the swap can be done with an existent C++ function.

Here is your code reorganized and using regular expressions that I tried to explain as much as possible:

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

using std::string;

struct Line {
    int expr;   // Expression used to compare
    string text;    // Original line without initial number
};

int main() {
    std::regex linePattern(
        "\\d+"      // 1 or more digits
        "\\. "      // '. ' (dot followed by 1 space)
        "("         // begin char group #1
           ".*"     // zero or more chars
           "\\("    // '(' (left parenthesis)
           "(\\d+)" // char group #2 (suratno: 1+ digits)
           ":"      // ':' (colon)
           "(\\d+)" // char group #3 (ayatno: 1+ digits)
           "\\)"    // ')' (right parenthesis)
        ")"         // end char group #1
    );
    std::smatch groups;         // Regular expression found char groups
    std::vector<Line> lines;    // Vector to store the readed lines

    // Read lines parsing content
    std::ifstream fin("text.txt");
    if(!fin){
        std::cerr << "Cannot open file 'text.txt'! Quitting.\n";
        return 1;
    }
    string line;
    while (std::getline(fin, line))
        if (std::regex_search(line, groups, linePattern) && groups.size() > 0) {
            int suratno = std::stoi(groups[2]);
            int ayatno = std::stoi(groups[3]);
            int compExpr = suratno * 10000 + ayatno; // assumes ayatno < 10,000
            lines.push_back({ compExpr, groups[1] });
        }
    fin.close();

    // sort algorithm (better start in 1)
    for (size_t i = 1; i < lines.size(); i++)
        for (size_t j = i; j > 0 && lines[j].expr < lines[j - 1].expr; j--)
            std::swap(lines[j], lines[j - 1]);

    std::ofstream fout("newtext.txt");
    if(!fout){
        std::cerr << "Cannot open output file 'orderedquranorders.txt'! Quitting.\n";
        return 1;
    }
    for (size_t i = 0; i < lines.size(); i++)
        fout << i + 1 << ". " << lines[i].text << std::endl;
    fout.close();

    std::cout << lines.size() << " orders successfully sorted and written.\n";
    return 0;
}

Note: The regular expression is really one string "\\d+\\. (.*\\((\\d+):(\\d+)\\))", I used a C/C++ feature that concatenates strings separated by spaces before compilation, so the compiler sees only one string.

Don't forget to compile with -std=c++11 option.

Community
  • 1
  • 1
Wilfredo Pomier
  • 1,091
  • 9
  • 12
0

using namespace std; is considered bad practice and can be dangerous sometimes. Check this

Here is your solution:

#include <iostream>
#include <fstream>
#include <string>

int main()
{
    int suratno[100], ayatno[100];
    std::string order[100];

    char ch;
    int count = 0;
    int tempInt;
    std::string tempStr;

    std::ifstream fin;
    fin.open("text.txt");

    if (!fin)
    {
        std::cout << "Cannot open file \'text.txt\'! Quitting.\n";
        exit(0);
    }
    else
    {
        while (fin)
        {
            fin.get(ch); //gets the numbers
            fin.get(ch); //gets .

            getline(fin, order[count], '('); //allegedly it removes the delimiter char from stream too

            fin >> suratno[count];
            fin.get(ch); //gets :
            fin >> ayatno[count];
            fin.get(ch); //gets )
            fin.get(ch); //gets \n

            std::cout << count + 1 << "." << order[count] << "(" << suratno[count] << ":" << ayatno[count] << ")\n";
            count++;
        }
    }
    fin.close();
    std::cout << std::endl;

    // sort algorithm (we must sort two times)
    for (int i = 0; i < count; i++)
    {
        for (int j = i; j > 0 && suratno[j] < suratno[j - 1]; j--)
        {
            tempInt = suratno[j];
            suratno[j] = suratno[j - 1];
            suratno[j - 1] = tempInt;

            tempInt = ayatno[j];
            ayatno[j] = ayatno[j - 1];
            ayatno[j - 1] = tempInt;

            tempStr = order[j];
            order[j] = order[j - 1];
            order[j - 1] = tempStr;
        }
    }

    for (int i = 0; i < count; i++)
    {
        for (int j = i; j > 0 && suratno[j] == suratno[j - 1] && ayatno[j] < ayatno[j - 1]; j--)
        {
            tempInt = ayatno[j];
            ayatno[j] = ayatno[j - 1];
            ayatno[j - 1] = tempInt;

            tempInt = suratno[j];
            suratno[j] = suratno[j - 1];
            suratno[j - 1] = tempInt;

            tempStr = order[j];
            order[j] = order[j - 1];
            order[j - 1] = tempStr;
        }       
    }

    // print the sorted list just to check
    for (int i = 0; i < count; i++)
    {
        std::cout << i + 1 << "." << order[i] << "(" << suratno[i] << ":" << ayatno[i] << ")\n";
    }

    // write sorted list to output file
    std::ofstream fout;
    fout.open("newtext.txt");

    if (!fout)
    {
        std::cout << "Cannot open output file\'orderedquranorders.txt\'!Quitting.\n";
        exit(0);
    }
    else
    {
        for (int i = 0; i < count; i++)
        {
            fout << i + 1 << "." << order[i] << "(" << suratno[i] << ":" << ayatno[i] << ")\n";
        }
    }
    fout.close();

    std::cout << std::endl;
    std::cout << count << " orders successfully sorted and written.\n";

    return 0;
}
Community
  • 1
  • 1
yahiheb
  • 147
  • 9