Sorting a custom struct in GArray

I have a simple data structure with two floats. I would like to sort using one of the values as a key (dist). g_array_sort isn’t returning the expected output

$ ./sort 
Before:
d: 1.200000, dot: 3.200000
d: 0.400000, dot: 4.200000
d: 2.400000, dot: 0.200000
d: 0.100000, dot: 0.300000

After:
d: 0.100000, dot: 0.300000
d: 1.200000, dot: 3.200000
d: 0.400000, dot: 4.200000
d: 2.400000, dot: 0.200000

I would expect

After:
d: 0.100000, dot: 0.300000
d: 0.400000, dot: 4.200000
d: 1.200000, dot: 3.200000
d: 2.400000, dot: 0.200000

The code is below:

#include <glib.h>
#include <math.h>

struct pair
{
    gfloat dist;
    gfloat dot;
};

static gint
cmppairdist (gconstpointer a, gconstpointer b)
{
    const struct pair* _a = a;
    const struct pair* _b = b;

    return _a->dist - _b->dist;
}

gint main(gint argc, gchar *argv[]) { 
    GArray * pairs;
    struct pair p;
    struct pair *t;

    pairs = g_array_new(FALSE, FALSE, sizeof(struct pair));
    
    p = (struct pair){ 1.2f, 3.2f };
    g_array_append_val(pairs, p);

    p = (struct pair){ 0.4f, 4.2f };
    g_array_append_val(pairs, p);

    p = (struct pair){ 2.4f, 0.2f };
    g_array_append_val(pairs, p);

    p = (struct pair){ 0.1f, 0.3f };
    g_array_append_val(pairs, p);


    g_print("Before:\n");
    for(size_t n = 0; n < pairs->len; n++)
    {
        t = &g_array_index(pairs, struct pair, n);
        g_print("d: %f, dot: %f\n", t->dist, t->dot);
    }

    g_array_sort(pairs, cmppairdist);
    g_print("\nAfter:\n");

    for(size_t n = 0; n < pairs->len; n++)
    {
        t = &g_array_index(pairs, struct pair, n);
        g_print("d: %f, dot: %f\n", t->dist, t->dot);
    }

    g_array_free(pairs, TRUE);

    return 0;
}

What I’m doing wrong? Any other coding hints?

GCompareFunc wants a specific return value: https://developer.gnome.org/glib/stable/glib-Doubly-Linked-Lists.html#GCompareFunc

You’re just returning the difference of two items, which is even a float and will be cast to an int when returning from the function. Compare the two values and return 0, 1, or -1.

Indeed. It worked. Is there any design reason to use fixed values -1, 0, 1 instead negative/0/positive?

IMHO it avoid one more branching.

The docs say: negative value if a < b ; zero if a = b ; positive value if a > b

The problem is that you e.g. return 0.4 - 0.1 which is getting converted to an integer, so ends up being just 0.

I understand tthat doc says that. Thank you for that. I have fixed and it worked.

Do you know why the design choice of GCompareFunc takes only values -1, 0 and 1 instead negative/0/positive.

Because using negatives and positives, returning the difference between two values would be enough.

Using -1,0 and 1 I had to do:

gfloat diff = _a->d - _b->d;
if (diff > 0)
    return 1;
else if(diff < 0)
    return -1;
else
    return 0;
}

The function does not have to return (-1, 0, 1), but you need to return an integer value, and you were returning a floating point value that got coerced into an integer.

Try printing the value of (int) (__a->d - _b->d) and see what it says. :wink:

Ok! For example (int)-0.3 becomes 0. Hence equal. Thank you all.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.