Home > Back-end >  Sorting a structure by multiple columns in C
Sorting a structure by multiple columns in C

Time:02-12

Consider a simple struct

typedef struct test {
int num;
double val;
} test;

int main()
{

test test[5]={ {5,4.3}, {1,0.9}, {1,0.3}, {1,3.2}, {5,1.1}};

for(int i=0; i<5; i  ){
    printf("%d: %f\n", test[i].num, test[i].val);
}
    return 0;
}

How do we sort it by the first column and then the next one?

Intended Output:

1: 0.300000
1: 0.900000
1: 3.200000
5: 1.100000
5: 4.300000

CodePudding user response:

The key to using qsort() is writing the compare function. The prototype is:

int compare (const void *a, const void *b)

Don't let your eyes roll back in your head. a and b are just pointers to elements of the array that will be compared in the compare() function. The function returns -1 if a sorts before b, 0 if they are equal, and 1 if b sorts before a. All you need to do with a and b is cast to the proper type and then make the desired comparison (ascending, descending, etc..).

In the case you have two values you wish to compare, you simply compare the first, and if they are NOT equal, you provide a return indicating how they should sort on the first value. (your .num member) If the first values with a and b ARE equal, then you provide a return based on the comparison of the second value (your .val member).

You can write the compare() function as:

int compare (const void *a, const void *b)
{
    test *x = (test *)a,
         *y = (test *)b;
    
    /* if ->num not equal, sort by ->num */
    if (x->num != y->num)
      return (x->num > y->num) - (x->num < y->num);
    
    /* otherwise, sort by val */
    return (x->val > y->val) - (x->val < y->val);
}

A short example that sorts the test array (renamed arr):

#include <stdio.h>
#include <stdlib.h>

typedef struct test {
  int num;
  double val;
} test;

int compare (const void *a, const void *b)
{
    test *x = (test *)a,
         *y = (test *)b;
    
    /* if ->num not equal, sort by ->num */
    if (x->num != y->num)
      return (x->num > y->num) - (x->num < y->num);
    
    /* otherwise, sort by val */
    return (x->val > y->val) - (x->val < y->val);
}

int main()
{

  test arr[]={ {5,4.3}, {1,0.9}, {1,0.3}, {1,3.2}, {5,1.1}};
  size_t nmemb = sizeof arr/sizeof *arr;
  
  qsort (arr, nmemb, sizeof *arr, compare);
  
  for (size_t i = 0; i < nmemb; i  ){
      printf ("%d: %f\n", arr[i].num, arr[i].val);
  }
}

Example Use/Output

$ ./bin/qsortstruct_test
1: 0.300000
1: 0.900000
1: 3.200000
5: 1.100000
5: 4.300000

Read the link I posted in the comment and the answer here and let me know if you have further questions.

  •  Tags:  
  • c
  • Related