сортировка двумерного массива на основе первого столбца

У меня есть файл temp2.dat, который выглядит так:

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

Теперь я хочу написать функцию в C для сортировки этих 4 столбцов в порядке возрастания, но только на основе значений первого столбца. Я попытался изменить следующий код, но это не удалось:

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;
}

Может ли кто-нибудь помочь мне сделать это? Ожидаемый результат должен выглядеть так:

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

person user177196    schedule 08.03.2018    source источник
comment
Ваша compare функция странная. Пожалуйста, посмотрите несколько примеров, предположительно, qsort, и будьте осторожны при тестировании значений с плавающей запятой на равенство. Опубликуйте минимальный, полный и проверяемый пример, демонстрирующий проблему.   -  person Weather Vane    schedule 09.03.2018
comment
return m->k > n->k; и return m->x > n->x; бесполезны, они никогда не будут достигнуты, вы можете вернуть только 1 объект из функции. И я настоятельно рекомендую добавить несколько скобок { ... } к вашему утверждению if, чтобы сделать его понятным, или, по крайней мере, изменить отступ. То, что у вас есть сейчас, вводит в заблуждение.   -  person yano    schedule 09.03.2018
comment
@yano: большое спасибо. Я бы отметил этот момент в следующий раз.   -  person user177196    schedule 09.03.2018


Ответы (2)


Попробуйте эту функцию сравнения

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;
}

Это сравнит первый столбец x. Если x совпадает в двух элементах, он перемещается во второй столбец y. Если второй столбец такой же, он перемещается в третий столбец и так далее.

Нам нужна разница между двумя значениями. Пример, m->y - n->y. Функция сравнения должна возвращать целочисленное значение 0, отрицательное или положительное.

При сравнении значений double мы не можем использовать m->x - n->x, потому что возвращаемое значение для compare равно int. Вместо этого мы используем функцию сравнения.

Тестирование

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;
}

выход:

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
person Barmak Shemirani    schedule 08.03.2018
comment
Большое спасибо за вашу большую помощь! Если первый столбец не совпадает, каждый раз ваша функция compare() будет автоматически сдвигать элементы в той же строке, но в остальных столбцах, на 1 строку вниз? - person user177196; 09.03.2018
comment
Я распечатал вывод, он выглядит правильно. Он сортирует 1-й столбец, затем 2-й столбец и т.д. - person Barmak Shemirani; 09.03.2018

Во-первых, в C, если вам нужно более одного оператора внутри любого блока, вы должны окружить его { и }. Таким образом, ваши последние 3 оператора return никогда не будут достигнуты (отступ не имеет значения для компилятора, только для людей).

Во-вторых, когда вы вызываете return, ваш код не возвращается. Таким образом, вы можете использовать вложенные if для сравнения значений, если они одинаковы в некоторых столбцах. Что-то типа:

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;
}
person Bruno Ely    schedule 08.03.2018
comment
Я предполагаю, что правильная логика заключается в вычитании, а не в сравнении - person Patrick Roberts; 09.03.2018
comment
Ах, я пропустил тег qsort. Просто сделал вывод, что делает функция сравнения, из того, что написал OP. - person Bruno Ely; 09.03.2018
comment
@BrunoEly: Большое спасибо! Позвольте мне попробовать ваш код, чтобы увидеть, действительно ли он делает то, что я хочу. Вы пробовали это с приведенным выше образцом набора данных? - person user177196; 09.03.2018
comment
Примечание. Этого compare() достаточно для использования с qsort(), так как он также ожидает отрицательные возвращаемые значения. - person chux - Reinstate Monica; 09.03.2018