user177196
user177196

Reputation: 728

sorting 2-d array based on the first column

I have a temp2.dat file that looks like this:

0.060493 1 0.5 1
1.596961 0 0.1 2
0.87758  1 0.3 1.5
0.165453 1 0   3
0.07085  1 0.3 4
0.125379 1 0.2 3
0.454202 1 0.2 2
0.373227 1 0.3 1
0.131486 1 0.3 3
0.867477 0 0.5 4
0.122609 0 0.8 9

Now I want to write the function in C to sort these 4 columns in an increasing order but only based on the values of the first column. I tried modifying the following code but it failed:

struct data_t
{
    double x;
    int y;
    double z;
    double k;
};

int compare(const void *a, const void *b)
{
    const struct data_t *m = a;
    const struct data_t *n = b;
    if(m->x == n->x)
        return m->y > n->y;
        return m->z > n->z;
        return m->k > n->k;
    return m->x > n->x;
}

Could someone please help me do this? The expected result should look like this:

0.060493 1 0.5 1
0.07085  1 0.3 4
0.122609 0 0.8 9
0.125379 1 0.2 3
0.131486 1 0.3 3
................
0.87758  1 0.3 1.5
1.596961 0 0.1 2

Upvotes: 0

Views: 81

Answers (2)

Barmak Shemirani
Barmak Shemirani

Reputation: 31599

Try this compare function

int compare(const void *a, const void *b)
{
    const struct data_t *m = a;
    const struct data_t *n = b;

    if(m->x != n->x)
        return (m->x > n->x) - (m->x < n->x);

    if(m->y != n->y)
        return m->y - n->y;

    if(m->z != n->z)
        return (m->z > n->z) - (m->z < n->z);

    if(m->k != n->k)
        return (m->k > n->k) - (m->x < n->k);

    return 0;
}

This will compare the first column x. If x is the same in the two elements, it moves to the second column y. If the second column is the same, it moves to the third column and so on.

We want the difference between the two values. Example, m->y - n->y. The compare function should return an integer value 0, negative, or positive.

When comparing double values, we cannot use m->x - n->x, because the return value for compare is int. We use a comparison function instead.

Testing

struct data_t
{
    double x;
    int y;
    double z;
    double k;
};

int compare(const void *a, const void *b)
{
    const struct data_t *m = a;
    const struct data_t *n = b;

    if(m->x != n->x)
        return (m->x > n->x) ? 1 : -1;

    if(m->y != n->y)
        return m->y - n->y;

    if(m->z != n->z)
        return (m->z > n->z) ? 1 : -1;

    if(m->k != n->k)
        return (m->k > n->k) ? 1 : -1;

    return 0;
}

int main(void)
{
    struct data_t data[] = 
    { 
        { 0.060493, 3, 0.4, 7 },//1st column is the same
        { 0.060493, 2, 0.5, 8 },
        { 0.060493, 1, 0.6, 9 },

        { 0.060493, 3, 0.3, 4 },//1st & 2nd columns are the same
        { 0.060493, 3, 0.2, 5 },
        { 0.060493, 3, 0.1, 6 },

        { 0.060493, 1, 0.5, 3 },//1st & 2nd & 3rd columns are the same
        { 0.060493, 1, 0.5, 2 },
        { 0.060493, 1, 0.5, 1 },

        { 0.122609, 0, 0.8, 9 },
        { 0.125379, 1, 0.2, 3 },
        { 0.131486, 1, 0.3, 3 },
    };

    int count = sizeof(data) / sizeof(data[0]);
    qsort(data, count, sizeof(data[0]), compare);

    for(int i = 0; i < count; i++)
    {
        printf("%.6f %d %.1f %.0f\n",
            data[i].x, data[i].y, data[i].z, data[i].k);
    }

    return 0;
}

output:

0.060493 1 0.5 1
0.060493 1 0.5 2
0.060493 1 0.5 3
0.060493 1 0.6 9
0.060493 2 0.5 8
0.060493 3 0.1 6
0.060493 3 0.2 5
0.060493 3 0.3 4
0.060493 3 0.4 7
0.122609 0 0.8 9
0.125379 1 0.2 3
0.131486 1 0.3 3

Upvotes: 1

sleighty
sleighty

Reputation: 1075

First off, in C if you want more than one statement inside any block, you have to surround it with { and }. So your last 3 return statements would never be reached (the indentation does not matter for the compiler, only for humans).

Second, when you call return, your code does not come back. So you could use nested ifs to compare the values in case they are the same in some of the columns. Something like:

int compare(const void *a, const void *b)
{
    const struct data_t *m = a;
    const struct data_t *n = b;
    if(m->x == n->x) {
        if (m->y == n->y) {
            if (m->z == n->z) {
                return m->k > n->k;
            }
            return m->z > n->z;
        }
        return m->y > n->y;
    }
    return m->x > n->x;
}

Upvotes: 0

Related Questions