Thread: Complex Organization of an Output file based on specific guidelines

  1. #1
    Registered User
    Join Date
    Jan 2020
    Posts
    11

    Complex Organization of an Output file based on specific guidelines

    Hello, I'm looking for a way to organize a file with specific guidelines.

    The Text file outputs the following:
    Au[10,0]
    Au[11,0]
    Au[12,0]
    Au[0,0]
    Al[1,0]
    Al[0,0]
    Al[10,0]
    Al[5,0]
    Al[12,0]

    Keep in mind these terms could be outputted in any order! Also the this file can vary between 1 to 40 terms (20 Au and 20 Al).

    The guidelines are as such.
    - Al must be placed before Au
    then the rest of the order should follow
    - [0,0], [1,0], [10,0], [11,0],...[19,0], [2,0], [3,0], ...[9,0]

    So i am trying to find a clever way to organize the file alphabetically then numerically. below is the part of the code that i started making to try and accomplish my task. I've got the first guideline i believe but it seems to get more complicated.

    Code:
    char r;
    int    i, j, num;
    FILE *fptr6;
    
    int main()
    {
    
    
        fptr6 = fopen("File_For_Temp_Formatting.out", "r");
    
        num = calculated else where//irrelevant for this part
    
    
        for(i=1; i<=num-1; i++) {
            fscanf(fptr6, "%s", r);
            if(strstr(r, "Al")) {
    
    
                printf("%s\n", r);
            }
        }
    
    
        fseek(fptr6, 0, SEEK_SET); // Starts the File over
        for(i=1; i<=num-1; i++) {
            fscanf(fptr6, "%s", r);
            if(strstr(r, "Au")) {
                printf("%s\n", r);
            }
        }
    
        return 0;
    }
    My output from what i wrote.
    Al[1,0]
    Al[0,0]
    Al[10,0]
    Al[5,0]
    Au[10,0]
    Au[11,0]
    Au[12,0]
    Au[0,0]


    Now it gets funky. in the first for loop, it will scan line by line and if that line has a Al, it evaluates the loop. But now i need to have something that will basically ask if that line has a 0,0 and if it does print it but if it doesn't go to the next line and look for 0,0 and continue until it is found or not found. Then look for 1,0 but starting over from the beginning of the file. and so on and so forth following the guidelines.

    I Know i could construct a bunch of for loops and if statements to get what i desire but this is very unpractical. If anyone knows any other approach please let me know

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > - [0,0], [1,0], [10,0], [11,0],...[19,0], [2,0], [3,0], ...[9,0]
    There's no 19 in your example input.

    Post an example of actual input, and an actual desired output.


    Does this match your requirements?
    - sort by name in ascending lexicographical order (so Al comes before Au).
    - then sort by the first term in numerical ascending order, so 1 comes before 10.
    - then sort by the second term, in numerical ascending order.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    null pointer Structure's Avatar
    Join Date
    May 2019
    Posts
    338

    Thumbs up

    construct a bunch of for loops and if statements
    other approach
    Recursion (computer science) - Wikipedia
    "without goto we would be wtf'd"

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Quote Originally Posted by Structure View Post
    What are you talking about???

    @Tricica, all you need to do is read all the records into an array of structs and then sort the array. Note that you have not shown a numeric sort on the numbers, but an alphabetical sort. And the second number is always 0 in your examples. So if that's correct, you can do it like this:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define MAX_RECORDS 100
     
    typedef struct {
        char type[10];
        char x[10];
    } Record;
     
    int cmp_r(const void *a, const void *b) {
        Record *ra = (Record*)a, *rb = (Record*)b;
        int cmp = strcmp(ra->type, rb->type);
        return cmp ? cmp : strcmp(ra->x, rb->x);
    }
     
    int main() {
        FILE *fin = fopen("input.txt", "r");
     
        Record r[MAX_RECORDS];
        int n = 0;
     
        Record in;
        while (fscanf(fin, " %9[^[][%9[^,],%*d]", in.type, in.x) == 2) {
            if (n >= MAX_RECORDS) {
                fprintf(stderr, "Record array overflow.\n");
                break;
            }
            strcpy(r[n].type, in.type);
            strcpy(r[n].x, in.x);
            ++n;
        }
     
        qsort(r, n, sizeof *r, cmp_r);
     
        for (int i = 0; i < n; ++i)
            printf("%s[%s,0]\n", r[i].type, r[i].x);
     
        return 0;
    }
    If sanity prevails and it really is a numeric sort for the numbers, and the second number is not always 0, then something like the following. This example is also more robust in terms of the spacing.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
     
    #define MAX_LINE    256
    #define MAX_RECORDS 200
     
    typedef struct {
        char type[8];
        int x, y;
    } Record;
     
    int cmp_r(const void *a, const void *b) {
        Record *ra = (Record*)a, *rb = (Record*)b;
        int cmp = strcmp(ra->type, rb->type);
        if (cmp) return cmp;
        cmp = ra->x - rb->x;
        if (cmp) return cmp;
        return ra->y - rb->y;
    }
     
    int main() {
        FILE *fin = fopen("input.txt", "r");
     
        Record r[MAX_RECORDS];
        int n = 0;
     
        for (char line[MAX_LINE]; fgets(line, sizeof line, fin) != NULL; ) {
     
            Record in;
            if (sscanf(line, " %7[^[][%d ,%d ]", in.type, &in.x, &in.y) != 3)
                continue;
     
            if (n >= MAX_RECORDS) {
                fprintf(stderr, "Record array overflow.\n");
                break;
            }
     
            // strip space from end
            size_t len = strlen(in.type);
            while (len && isspace(in.type[len - 1])) --len;
            in.type[len] = '\0';
     
            r[n++] = in;
        }
     
        qsort(r, n, sizeof *r, cmp_r);
     
        for (int i = 0; i < n; ++i)
            printf("%s[%d,%d]\n", r[i].type, r[i].x, r[i].y);
     
        return 0;
    }
    Example input:
    Code:
    Au[10,1]
    Al[12,2]
     Au [ 11 , 1 ] 
    Au[2,1]
    Al[5,1]
    Au[10,0]
     
    Al[0,0]
    Au[0,0]
    Al[5,0]
    Al [ 0 , 1 ]
    Au[12,0]
    Al[10,1]
    Au [ 10 , 2 ] 
    Al[10,0]
     
    Al[12,0]
    Al[1,0]
    Au[11,0]
    Au[2,0]
    Al[12 , 1]
    Al[0,2]
    Au[2,2]
    Au[2,3]
    Au[4,0]
    Last edited by john.c; 01-23-2020 at 09:25 AM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  5. #5
    Registered User
    Join Date
    Jan 2020
    Posts
    11
    Hello, the actual input here is:

    Au[10,0]
    Au[11,0]
    Au[12,0]
    Au[0,0]
    Al[1,0]
    Al[0,0]
    Al[10,0]
    Al[5,0]
    Al[12,0]

    but this files varies from case to case and can have a total of 40 rows. for example it could be:

    Au[7,0]
    Au[4,0]
    Au[19,0]
    Au[10,0]

    Au[11,0]
    Au[12,0]
    Au[0,0]
    Al[1,0]
    Al[0,0]
    Al[10,0]
    Al[5,0]
    Al[19,0]

    so the desired out put from the above would be
    Al[0,0]
    Al[1,0]
    Al[10,0]
    Al[19,0]
    Al[5,0]
    Au[0,0]
    Au[10,0]
    Au[11,0]
    Au[12,0]
    Au[19,0]
    Au[4,0]
    Au[7,0]

    So yes your first statement matches my requirements but the second two don't. The second term is always zero so i only have to worry about the first.

    but the first term should be organized in a order that follows
    0 - 1 - 10 - 11 - 12 - 13 -14 -15 -16 -17 - 18 - 19 - 2 -3-4-5-6-7-8-9
    So the 10-19 come before 2-9 because they have a "1" in them

  6. #6
    Registered User
    Join Date
    Jan 2020
    Posts
    11
    Hello, This is excellent! but it isn't exactly what i require as a output... Your code sorts the file in ascending order from 0 - 19 but the order i require isn't as simple. It needs to be 0 - 1 - 10 - 11 - 12 - 13 -14 -15 -16 -17 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9
    so the values 10 - 19 skip 2 - 9 because they have that leading 1
    And i am still a beginner to C so your code is a bit intimidating so if i have any questions can i send them your way?

    Quote Originally Posted by john.c View Post
    What are you talking about???

    @Tricica, all you need to do is read all the records into an array of structs and then sort the array. Note that you have not shown a numeric sort on the numbers, but an alphabetical sort. And the second number is always 0 in your examples. So if that's correct, you can do it like this:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define MAX_RECORDS 100
     
    typedef struct {
        char type[10];
        char x[10];
    } Record;
     
    int cmp_r(const void *a, const void *b) {
        Record *ra = (Record*)a, *rb = (Record*)b;
        int cmp = strcmp(ra->type, rb->type);
        return cmp ? cmp : strcmp(ra->x, rb->x);
    }
     
    int main() {
        FILE *fin = fopen("input.txt", "r");
     
        Record r[MAX_RECORDS];
        int n = 0;
     
        Record in;
        while (fscanf(fin, " %9[^[][%9[^,],%*d]", in.type, in.x) == 2) {
            if (n >= MAX_RECORDS) {
                fprintf(stderr, "Record array overflow.\n");
                break;
            }
            strcpy(r[n].type, in.type);
            strcpy(r[n].x, in.x);
            ++n;
        }
     
        qsort(r, n, sizeof *r, cmp_r);
     
        for (int i = 0; i < n; ++i)
            printf("%s[%s,0]\n", r[i].type, r[i].x);
     
        return 0;
    }
    If sanity prevails and it really is a numeric sort for the numbers, and the second number is not always 0, then something like the following. This example is also more robust in terms of the spacing.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
     
    #define MAX_LINE    256
    #define MAX_RECORDS 200
     
    typedef struct {
        char type[8];
        int x, y;
    } Record;
     
    int cmp_r(const void *a, const void *b) {
        Record *ra = (Record*)a, *rb = (Record*)b;
        int cmp = strcmp(ra->type, rb->type);
        if (cmp) return cmp;
        cmp = ra->x - rb->x;
        if (cmp) return cmp;
        return ra->y - rb->y;
    }
     
    int main() {
        FILE *fin = fopen("input.txt", "r");
     
        Record r[MAX_RECORDS];
        int n = 0;
     
        for (char line[MAX_LINE]; fgets(line, sizeof line, fin) != NULL; ) {
     
            Record in;
            if (sscanf(line, " %7[^[][%d ,%d ]", in.type, &in.x, &in.y) != 3)
                continue;
     
            if (n >= MAX_RECORDS) {
                fprintf(stderr, "Record array overflow.\n");
                break;
            }
     
            // strip space from end
            size_t len = strlen(in.type);
            while (len && isspace(in.type[len - 1])) --len;
            in.type[len] = '\0';
     
            r[n++] = in;
        }
     
        qsort(r, n, sizeof *r, cmp_r);
     
        for (int i = 0; i < n; ++i)
            printf("%s[%d,%d]\n", r[i].type, r[i].x, r[i].y);
     
        return 0;
    }
    Example input:
    Code:
    Au[10,1]
    Al[12,2]
     Au [ 11 , 1 ] 
    Au[2,1]
    Al[5,1]
    Au[10,0]
     
    Al[0,0]
    Au[0,0]
    Al[5,0]
    Al [ 0 , 1 ]
    Au[12,0]
    Al[10,1]
    Au [ 10 , 2 ] 
    Al[10,0]
     
    Al[12,0]
    Al[1,0]
    Au[11,0]
    Au[2,0]
    Al[12 , 1]
    Al[0,2]
    Au[2,2]
    Au[2,3]
    Au[4,0]

  7. #7
    Registered User
    Join Date
    Jan 2020
    Posts
    11
    All I could think of is repeating this for loop
    Code:
     for(i=1; i<=num-1; i++) {
            fscanf(fptr6, "%s", r);
            if(strstr(r, "Al")) {
                if(strstr(r, "[0,0]")) {
                    printf("%s\n", r);
        }   }   }
     fseek(fptr6, 0, SEEK_SET); // Starts the File over
     for(i=1; i<=num-1; i++) {
            fscanf(fptr6, "%s", r);
            if(strstr(r, "Al")) {
                if(strstr(r, "[1,0]")) {
                    printf("%s\n", r);
        }   }   }
    Changing the [0,0] each time so it makes sure it looks for that position first and if it doesn't find it it'll go to the next loop and look for [1,0] and so on and so forth until it transitions to Au.

    But this required 40 for loops (That do work).... not the most efficient and cost friendly / timely process. Especially because i'll be using this code for a optimization sequence which will go thru thousands of iterations.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > It needs to be 0 - 1 - 10 - 11 - 12 - 13 -14 -15 -16 -17 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9
    OK, so you tweak john.c's code a little bit.

    > cmp = ra->x - rb->x;
    You basically have 4 variations to compare:
    - Both x's are < 10 - easy, simple comparison
    - Both x's are >= 10 - easy, simple comparison
    - ra->x is < 10 and rb->x is >= 10, compare ra->x with rb->x / 10
    - you can guess what the last case looks like.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    0 - 1 - 10 - 11 - 12 - 13 -14 -15 -16 -17 - 18 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9
    But isn't that just alphabetical order, like the first version I posted uses? That version also assumes the second number (after the comma) is always 0, but that seems to be your situation. It also assumes that there's no extra spaces after the Al or Au, hence no need to strip them. It also happens to assume no space just before the comma after the first number, but that can easily be fixed with a space before the comma in the format string, which I would've put in if I had thought about it.

    You can, of course, ask questions; but do so here, not by PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  10. #10
    null pointer Structure's Avatar
    Join Date
    May 2019
    Posts
    338
    this works...
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define importFile "import.txt"
    #define maxRows 40
    #define maxLine 16
    
    char strings[maxRows][maxLine], sorts[maxRows];
    
    char *import(char filename[]) {
        FILE* file = fopen(filename, "r");
        char line[maxLine]; int count = 0;
        while (fgets(line, sizeof(line), file)) {
            strcpy(strings[count], line); 
            strings[count][strlen(strings[count])-1] = 0;
            count++;
        };
        fclose(file);
    };
    
    void lexiSort() {
        for (int i = 0; i < maxRows; i++) {
            for (int j = (i+1); j < maxLine; j++) {
                if (strcmp(strings[i], strings[j]) > 0) {
                    strcpy(sorts, strings[i]);
                    strcpy(strings[i], strings[j]);
                    strcpy(strings[j], sorts);
                };
            };
        };
    };
    
    void displayResult() {
        for (int i=0;i < maxRows;i++) {
            if (strings[i][0] != 0) {
                printf("%s\n",strings[i]);
            };
        };
    };
    
    int main(int args,char *argv[]) {
        import(importFile); 
        lexiSort();
        displayResult();
        return 0;
    };
    reference:
    C Program to Sort Elements in Lexicographical Order (Dictionary Order)
    Last edited by Structure; 01-23-2020 at 12:25 PM.
    "without goto we would be wtf'd"

  11. #11
    null pointer Structure's Avatar
    Join Date
    May 2019
    Posts
    338
    multipost fail... my bad.
    Last edited by Structure; 01-23-2020 at 12:26 PM.
    "without goto we would be wtf'd"

  12. #12
    null pointer Structure's Avatar
    Join Date
    May 2019
    Posts
    338
    .....
    Last edited by Structure; 01-23-2020 at 12:32 PM.
    "without goto we would be wtf'd"

  13. #13
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Structure makes a good point that you can just sort the entire lines as strings.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define MAX_RECORDS 200
    #define MAX_LINE    100
     
    int cmp_r(const void *a, const void *b) {
        return strcmp((char*)a, (char*)b);
    }
     
    int main() {
        FILE *fin = fopen("input.txt", "r");
     
        char r[MAX_RECORDS][MAX_LINE];
        int n = 0;
     
        char in[MAX_LINE];
        while (fgets(in, sizeof in, fin) != NULL) {
            if (n >= MAX_RECORDS) {
                fprintf(stderr, "Record array overflow.\n");
                break;
            }
            strcpy(r[n], in);
            ++n;
        }
     
        fclose(fin);
     
        qsort(r, n, sizeof *r, cmp_r);
     
        for (int i = 0; i < n; ++i)
            fputs(r[i], stdout);
     
        return 0;
    }
    Last edited by john.c; 01-23-2020 at 12:53 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  14. #14
    Registered User
    Join Date
    Jan 2020
    Posts
    11
    @john.c and @Structure @Salem

    Sorting the entire line as a string make so much sense and i can follow the logic in your codes well. But what if i needed to know the original placement of each variable. i.e for the file below

    Au[10,0]
    Al[12,0]
    Au[9,0]
    Al[5,0]
    Al[6,0]
    Al[0,0]
    Au[12,0]
    Au[18,0]
    Al[10,0]
    Al[1,0]
    Au[11,0]
    Al[19,0]
    Au[2,0]
    Au[4,0]

    Al[0,0] will be organized to the first position but how can i extract its original position (Which would be the 6th). Similarly Al[1,0] will be organized to the second position but i would also need to know its original position (Which would be the 10th). And so on. So i can store these positions in a vector. In the case of the example above i would want.
    Positions = [6, 10, 9, 2, 12, 4, ....]
    the next 4 numbers in the vector are from the below variables
    9th = Al[10,0], 2nd = Al[12,0], 12th = Al[19,0], 4th = Al[5,0]

    So basically finding the position (i) of strings[i] that corresponds to the values from lowest to highest. Any help would be great. Below is some of my thoughts on how to solve this.

    i was thinking of putting in a count, at the second for loop of lexisort to see how many strings it went thru before finding the lowest values. But strings[] gets mixed up and the variables get out of original order so it would only help my case for the first variable.

    Code:
    void lexiSort() {
        for (int i = 0; i < maxRows; i++) {
            for (int j = (i+1); j < maxLine; j++) {
                if (strcmp(strings[i], strings[j]) > 0) {
                    strcpy(sorts, strings[i]);
                    strcpy(strings[i], strings[j]);
                    strcpy(strings[j], sorts);
                };
            };
        };
    };
    This is another process i'm thinking of:
    Go thru the same if statement but instead of sorting the lowest value string to the top, it would be replaced with a large value, such as Z, and then it would count how many strings where passed to get to the last replacement. This would be the original location.
    But only the last string would be preeminently replaced in order for the next lowest to be found in its original location.

    Just a thought, this is what i'll be trying as of right now

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Tricica
    Al[0,0] will be organized to the first position but how can i extract its original position (Which would be the 6th). Similarly Al[1,0] will be organized to the second position but i would also need to know its original position (Which would be the 10th). And so on. So i can store these positions in a vector.
    When you need to retain both an original ordering and a sorted ordering (or even multiple sorted orderings according to different comparison criteria), one approach is to sort a container of pointers instead. So the original ordering does not change, but by accessing the sorted container of pointers, you can obtain the sorted ordering for each item. This is basically creating an index for the items (think of an index for a book, or if you know about relational databases, an index for a table).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 10-05-2016, 12:15 PM
  2. Naming an output file based on an input file name
    By mbxs3 in forum C Programming
    Replies: 4
    Last Post: 09-07-2013, 06:30 PM
  3. output of complex numbers
    By wablackwell in forum C Programming
    Replies: 3
    Last Post: 09-26-2012, 09:43 PM
  4. Complex struct organization (network/packet-related)
    By brooksbp in forum C Programming
    Replies: 6
    Last Post: 08-16-2008, 10:38 PM
  5. General Guidelines on Preventing Header File collision
    By stanlvw in forum C++ Programming
    Replies: 12
    Last Post: 07-05-2008, 04:02 AM

Tags for this Thread