在C中按另一个数组对多维数组进行排序

时间:2021-08-22 21:32:18

I am beginner with C.I have two files second.txt

我是C.的初学者。我有两个文件second.txt

0 0 1.200
1 0 1.200
2 0 1.200
3 0 1.200
1 1 1.400 
2 1 1.420
3 1 1.480
0 1 1.400
0 2 1.500
2 2 1.520
3 2 1.540
1 2 1.500

newindex.txt

newindex.txt

0 0
1 0
2 0
3 0
0 1
1 1
2 1
3 1
0 2
1 2
2 2
3 2

I want to write file like this(third column value should be written in proper indexing)

我想写这样的文件(第三列值应该用正确的索引编写)

0.0 0.0 1.2
1.0 0.0 1.2
2.0 0.0 1.2
3.0 0.0 1.2
0.0 1.0 1.4
1.0 1.0 1.4
2.0 1.0 1.42
3.0 1.0 1.48
0.0 2.0 1.5
1.0 2.0 1.5
2.0 2.0 1.52
3.0 2.0 1.54

I have written this comparison function

我写过这个比较函数

 int my_cmp(const void *a_, const void *b_,void *arg_)
 {
   const int *a = a_, *b = b_;

   if(B[*a][1] == B[*b][1])
       return 0;
    else if (B[*a][1] < B[*b][1])
        return -1;
    else
        return 1;

}

But what to do next?Should I use qsort,if yes,how?

但接下来该怎么做?我应该使用qsort,如果是的话,怎么样?

1 个解决方案

#1


2  

Since you are only interested in the float value at the end of each line in second.txt, you need only read those values into an array to be sorted. The newindex.txt file provides everything else you will need to complete each line in your new output file. In essence all you are doing is reading the floats from second.txt sorting them, and adding them to the end of each line in newindex.txt

由于您只对second.txt中每行末尾的浮点值感兴趣,因此只需将这些值读入要排序的数组中。 newindex.txt文件提供了完成新输出文件中每一行所需的所有其他内容。本质上你所做的就是从second.txt中读取浮点数,然后将它们添加到newindex.txt中每行的末尾。

The code below will read from second.txt and newindex.txt (by default) or take the file names provided by the first and second arguments to the program. (you must provide both arguments to provide an alternative file for newindex.txt)

下面的代码将从second.txt和newindex.txt(默认情况下)读取,或者获取程序的第一个和第二个参数提供的文件名。 (您必须提供两个参数才能为newindex.txt提供替代文件)

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

enum { MAXC = 16, MAXF = 32 };  /* constants for buffer and array size */

int cmpfloat (const void *a, const void *b);  /* qsort comparison */
void rmlf (char *s);                          /* trim newline    */

int main (int argc, char **argv) {

    size_t i = 0, idx = 0;
    float ftmp, second[MAXF] = {0.0};
    char buf[MAXC] = "";
    FILE *fp = fopen (argc > 1 ? argv[1] : "second.txt", "r");

    if (!fp) {  /* validate "second.txt" open for reading */
        fprintf (stderr, "error: file open failed (second).\n");
        return 1;
    }

    while (idx < MAXF && fgets (buf, MAXC, fp)) /* read each line    */
        if (sscanf (buf, " %*d %*d %f", &ftmp)) /* parse float value */
            second[idx++] = ftmp;      /* add to array, update index */
    fclose (fp);

    qsort (second, idx, sizeof *second, cmpfloat); /* sort floats */

    /* open/validate "newindex" for reading */
    if (!(fp = fopen (argc > 2 ? argv[2] : "newindex.txt", "r"))) {
        fprintf (stderr, "error: file open failed (newindex).\n");
        return 1;
    }

    while (i < idx && fgets (buf, MAXC, fp)) {  /* read each line */
        rmlf (buf);                             /* trim newline   */
        printf ("%s %.2f\n", buf, second[i++]); /* write sorted output */
    }

    fclose (fp);

    return 0;
}

/* qsort comparison for floats */
int cmpfloat (const void *a, const void *b)
{
    /* (a > b) - (a < b) */
    return (*(float *)a > *(float *)b) - (*(float *)a < *(float *)b);
}

/* trim newline from end of string */
void rmlf (char *s)
{
    if (!s || !*s) return;
    for (; *s && *s != '\n'; s++) {}
    *s = 0;
}

Example Output

示例输出

Using your data files as input, you can produce your desired output.

使用数据文件作为输入,可以生成所需的输出。

$ ./bin/qsortnewindex
0 0 1.20
1 0 1.20
2 0 1.20
3 0 1.20
0 1 1.40
1 1 1.40
2 1 1.42
3 1 1.48
0 2 1.50
1 2 1.50
2 2 1.52
3 2 1.54

Look it over and let me know if you have any questions.

仔细看看,如果您有任何疑问,请告诉我。


Writing Output with fwrite

用fwrite写输出

As indicated in the comment, if you are intending to write output with fwrite to a file, you will be writing the output in binary format. That is fine, but understand if you want to look at the file, you will see nothing but gibberish (data, not characters). If you want to write what you see printed to the screen to a file as formatted text, then you want the fprintf function which works the same as printf except you provide a FILE * stream pointer to which the output is written.

如注释中所示,如果您打算使用fwrite将输出写入文件,则将以二进制格式编写输出。这很好,但要明白,如果你想查看文件,除了胡言乱语(数据,而不是字符),你什么都看不到。如果你想把你在屏幕上看到的内容写成文件作为格式化文本,那么你需要fprintf函数和printf一样工作,除了你提供了一个写入输出的FILE *流指针。

(If you want the formatted output in a file, the simple way is to redirect the original program output to a file from the command line, e.g. ./qsortnewindex > filename.txt, however that doesn't provide the decimal points you show as your desired output.)

(如果您希望将格式化的输出放在文件中,那么简单的方法是将原始程序输出重定向到命令行中的文件,例如./qsortnewindex> filename.txt,但是这不会提供您显示为的小数点你想要的输出。)

Since you need to understand both reading and writing with fwrite as well as with fprintf, the example below shows both. While there was no requirement to use a 2D array to hold all values at once, it does simplify the fwrite call, so I have rearranged the storage so that all values (newindex.txt and sorted second.txt) are held in the 2D array named creatively enough array.

由于您需要使用fwrite以及fprintf来理解读取和写入,下面的示例显示了两者。虽然没有要求使用2D数组同时保存所有值,但它确实简化了fwrite调用,因此我重新安排了存储,以便所有值(newindex.txt和sorted second.txt)都保存在2D数组中创造性地命名为数组。

Go over each part of the example to insure you understand what it taking place. Since you cannot simply look at the binary data and confirm it was properly written, the end of the code reads the data back in from the binary output file newindex.dat and displays that information on screen. (you can look at it with programs like hexdump, od, or bvi)

浏览示例的每个部分,以确保您了解它发生了什么。由于您不能简单地查看二进制数据并确认它已正确写入,因此代码末尾会从二进制输出文件newindex.dat中读回数据并在屏幕上显示该信息。 (您可以使用hexdump,od或bvi等程序查看)

The formatted text file created is newindex.dat.txt. You can simply look at that file to confirm the output. Also note, the qsort compare function has changed to sort on the 3rd column of the array.

创建的格式化文本文件是newindex.dat.txt。您只需查看该文件即可确认输出。另请注意,qsort compare函数已更改为对数组的第3列进行排序。

Let me know if you have any questions.

如果您有任何疑问,请告诉我。

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

/* constants for new index cols, buffer and second array size */
enum { NCOL = 3, MAXC = 11, MAXF = 12 };

int cmpfloat (const void *a, const void *b);  /* qsort comparison */

int main (int argc, char **argv) {

    size_t i = 0, idx = 0;
    float ftmp, ftmp2, array[MAXF][NCOL] = {{0.0}};
    char buf[MAXC] = "";
    FILE *fp = fopen (argc > 1 ? argv[1] : "second.txt", "r");

    if (!fp) {  /* validate "second.txt" open for reading */
        fprintf (stderr, "error: file open failed (second).\n");
        return 1;
    }

    while (idx < MAXF && fgets (buf, MAXC, fp))   /* read each line    */
        if (sscanf (buf, " %*d %*d %f", &ftmp))   /* parse float value */
            array[idx++][NCOL-1] = ftmp; /* add to array, update index */
    fclose (fp);

    /* sort floats in last col */
    qsort (array, idx, sizeof *array, cmpfloat);

    /* open/validate "newindex" for reading */
    if (!(fp = fopen (argc > 2 ? argv[2] : "newindex.txt", "r"))) {
        fprintf (stderr, "error: file open failed (newindex).\n");
        return 1;
    }

    /* read each line, parse values into float array */
    for (i = 0; i < idx && fgets (buf, MAXC, fp);) {
        if (sscanf (buf, " %f %f", &ftmp, &ftmp2) == 2) {
            array[i][0] = ftmp;
            array[i][1] = ftmp2;
            i++;
        }
        else
            fprintf (stderr, "error: failed to parse values from '%s'.\n",
                     "newindex.txt");
    }
    fclose (fp);

    if (i != idx) { /* validate rows match second.txt */
        fprintf (stderr, "error: mismatch in data between newindex and second.\n");
        return 1;
    }

    /* open/validate "newindex.dat" for output (binary) */
    if (!(fp = fopen (argc > 3 ? argv[3] : "newindex.dat", "w"))) {
        fprintf (stderr, "error: file open failed '%s'.\n",
                 "newindex.dat");
        return 1;
    }

    /* write array to output file in binary using fwrite */
    if (fwrite (array, sizeof *array, idx, fp) != idx)
        fprintf (stderr, "error: file write failed '%s'.\n",
                 "newindex.dat");

    if (fclose (fp))    /* check for error on close (errno set) */
        fprintf (stderr, "error: failure on file close '%s'.\n",
                 "newindex.dat");

    /* open/validate "newindex.dat.txt" for output (formatted text) */
    if (!(fp = fopen (argc > 3 ? argv[3] : "newindex.dat.txt", "w"))) {
        fprintf (stderr, "error: file open failed '%s'.\n",
                 "newindex.dat.txt");
        return 1;
    }

    /* write array to output file in formatted text using fprintf */
    for (i = 0; i < idx; i++)
        fprintf (fp, "%.1f %.1f %.2f\n", 
                array[i][0], array[i][1], array[i][2]);

    if (fclose (fp))    /* check for error on close (errno set) */
        fprintf (stderr, "error: failure on file close '%s'.\n",
                 "newindex.dat.txt");

    /* confirm output values -- open/validate "newindex.dat" */
    if (!(fp = fopen (argc > 3 ? argv[3] : "newindex.dat", "r"))) {
        fprintf (stderr, "error: file open failed '%s'.\n",
                 "newindex.dat");
        return 1;
    }

    float b[MAXF][NCOL] = {{0.0}};  /* read binary data into array */
    if (fread (b, sizeof *b, idx, fp) != idx)
        fprintf (stderr, "error: file write failed '%s'.\n",
                 "newindex.dat");

    fclose (fp);

    printf ("\narray values read from binary file '%s'.\n\n",
            "newindex.dat");
    for (i = 0; i < idx; i++)   /* output data from file */
        printf ("%.1f %.1f %.2f\n", b[i][0], b[i][1], b[i][2]);

    return 0;
}

/* qsort comparison for floats */
int cmpfloat (const void *a, const void *b)
{
    const float *ia = (const float *)a;
    const float *ib = (const float *)b;
    return (ia[NCOL-1] > ib[NCOL-1]) - (ia[NCOL-1] < ib[NCOL-1]);
}

Example Output

示例输出

The program reads the values written to the binary file newindex.dat using fwrite:

该程序使用fwrite读取写入二进制文件newindex.dat的值:

$ ./bin/qsortnewindex2

array values read from binary file 'newindex.dat'.

0.0 0.0 1.20
1.0 0.0 1.20
2.0 0.0 1.20
3.0 0.0 1.20
0.0 1.0 1.40
1.0 1.0 1.40
2.0 1.0 1.42
3.0 1.0 1.48
0.0 2.0 1.50
1.0 2.0 1.50
2.0 2.0 1.52
3.0 2.0 1.54

You can also confirm that the formatted text ouput file was created properly:

您还可以确认格式化的文本输出文件是否已正确创建:

$ cat newindex.dat.txt
0.0 0.0 1.20
1.0 0.0 1.20
2.0 0.0 1.20
3.0 0.0 1.20
0.0 1.0 1.40
1.0 1.0 1.40
2.0 1.0 1.42
3.0 1.0 1.48
0.0 2.0 1.50
1.0 2.0 1.50
2.0 2.0 1.52
3.0 2.0 1.54

#1


2  

Since you are only interested in the float value at the end of each line in second.txt, you need only read those values into an array to be sorted. The newindex.txt file provides everything else you will need to complete each line in your new output file. In essence all you are doing is reading the floats from second.txt sorting them, and adding them to the end of each line in newindex.txt

由于您只对second.txt中每行末尾的浮点值感兴趣,因此只需将这些值读入要排序的数组中。 newindex.txt文件提供了完成新输出文件中每一行所需的所有其他内容。本质上你所做的就是从second.txt中读取浮点数,然后将它们添加到newindex.txt中每行的末尾。

The code below will read from second.txt and newindex.txt (by default) or take the file names provided by the first and second arguments to the program. (you must provide both arguments to provide an alternative file for newindex.txt)

下面的代码将从second.txt和newindex.txt(默认情况下)读取,或者获取程序的第一个和第二个参数提供的文件名。 (您必须提供两个参数才能为newindex.txt提供替代文件)

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

enum { MAXC = 16, MAXF = 32 };  /* constants for buffer and array size */

int cmpfloat (const void *a, const void *b);  /* qsort comparison */
void rmlf (char *s);                          /* trim newline    */

int main (int argc, char **argv) {

    size_t i = 0, idx = 0;
    float ftmp, second[MAXF] = {0.0};
    char buf[MAXC] = "";
    FILE *fp = fopen (argc > 1 ? argv[1] : "second.txt", "r");

    if (!fp) {  /* validate "second.txt" open for reading */
        fprintf (stderr, "error: file open failed (second).\n");
        return 1;
    }

    while (idx < MAXF && fgets (buf, MAXC, fp)) /* read each line    */
        if (sscanf (buf, " %*d %*d %f", &ftmp)) /* parse float value */
            second[idx++] = ftmp;      /* add to array, update index */
    fclose (fp);

    qsort (second, idx, sizeof *second, cmpfloat); /* sort floats */

    /* open/validate "newindex" for reading */
    if (!(fp = fopen (argc > 2 ? argv[2] : "newindex.txt", "r"))) {
        fprintf (stderr, "error: file open failed (newindex).\n");
        return 1;
    }

    while (i < idx && fgets (buf, MAXC, fp)) {  /* read each line */
        rmlf (buf);                             /* trim newline   */
        printf ("%s %.2f\n", buf, second[i++]); /* write sorted output */
    }

    fclose (fp);

    return 0;
}

/* qsort comparison for floats */
int cmpfloat (const void *a, const void *b)
{
    /* (a > b) - (a < b) */
    return (*(float *)a > *(float *)b) - (*(float *)a < *(float *)b);
}

/* trim newline from end of string */
void rmlf (char *s)
{
    if (!s || !*s) return;
    for (; *s && *s != '\n'; s++) {}
    *s = 0;
}

Example Output

示例输出

Using your data files as input, you can produce your desired output.

使用数据文件作为输入,可以生成所需的输出。

$ ./bin/qsortnewindex
0 0 1.20
1 0 1.20
2 0 1.20
3 0 1.20
0 1 1.40
1 1 1.40
2 1 1.42
3 1 1.48
0 2 1.50
1 2 1.50
2 2 1.52
3 2 1.54

Look it over and let me know if you have any questions.

仔细看看,如果您有任何疑问,请告诉我。


Writing Output with fwrite

用fwrite写输出

As indicated in the comment, if you are intending to write output with fwrite to a file, you will be writing the output in binary format. That is fine, but understand if you want to look at the file, you will see nothing but gibberish (data, not characters). If you want to write what you see printed to the screen to a file as formatted text, then you want the fprintf function which works the same as printf except you provide a FILE * stream pointer to which the output is written.

如注释中所示,如果您打算使用fwrite将输出写入文件,则将以二进制格式编写输出。这很好,但要明白,如果你想查看文件,除了胡言乱语(数据,而不是字符),你什么都看不到。如果你想把你在屏幕上看到的内容写成文件作为格式化文本,那么你需要fprintf函数和printf一样工作,除了你提供了一个写入输出的FILE *流指针。

(If you want the formatted output in a file, the simple way is to redirect the original program output to a file from the command line, e.g. ./qsortnewindex > filename.txt, however that doesn't provide the decimal points you show as your desired output.)

(如果您希望将格式化的输出放在文件中,那么简单的方法是将原始程序输出重定向到命令行中的文件,例如./qsortnewindex> filename.txt,但是这不会提供您显示为的小数点你想要的输出。)

Since you need to understand both reading and writing with fwrite as well as with fprintf, the example below shows both. While there was no requirement to use a 2D array to hold all values at once, it does simplify the fwrite call, so I have rearranged the storage so that all values (newindex.txt and sorted second.txt) are held in the 2D array named creatively enough array.

由于您需要使用fwrite以及fprintf来理解读取和写入,下面的示例显示了两者。虽然没有要求使用2D数组同时保存所有值,但它确实简化了fwrite调用,因此我重新安排了存储,以便所有值(newindex.txt和sorted second.txt)都保存在2D数组中创造性地命名为数组。

Go over each part of the example to insure you understand what it taking place. Since you cannot simply look at the binary data and confirm it was properly written, the end of the code reads the data back in from the binary output file newindex.dat and displays that information on screen. (you can look at it with programs like hexdump, od, or bvi)

浏览示例的每个部分,以确保您了解它发生了什么。由于您不能简单地查看二进制数据并确认它已正确写入,因此代码末尾会从二进制输出文件newindex.dat中读回数据并在屏幕上显示该信息。 (您可以使用hexdump,od或bvi等程序查看)

The formatted text file created is newindex.dat.txt. You can simply look at that file to confirm the output. Also note, the qsort compare function has changed to sort on the 3rd column of the array.

创建的格式化文本文件是newindex.dat.txt。您只需查看该文件即可确认输出。另请注意,qsort compare函数已更改为对数组的第3列进行排序。

Let me know if you have any questions.

如果您有任何疑问,请告诉我。

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

/* constants for new index cols, buffer and second array size */
enum { NCOL = 3, MAXC = 11, MAXF = 12 };

int cmpfloat (const void *a, const void *b);  /* qsort comparison */

int main (int argc, char **argv) {

    size_t i = 0, idx = 0;
    float ftmp, ftmp2, array[MAXF][NCOL] = {{0.0}};
    char buf[MAXC] = "";
    FILE *fp = fopen (argc > 1 ? argv[1] : "second.txt", "r");

    if (!fp) {  /* validate "second.txt" open for reading */
        fprintf (stderr, "error: file open failed (second).\n");
        return 1;
    }

    while (idx < MAXF && fgets (buf, MAXC, fp))   /* read each line    */
        if (sscanf (buf, " %*d %*d %f", &ftmp))   /* parse float value */
            array[idx++][NCOL-1] = ftmp; /* add to array, update index */
    fclose (fp);

    /* sort floats in last col */
    qsort (array, idx, sizeof *array, cmpfloat);

    /* open/validate "newindex" for reading */
    if (!(fp = fopen (argc > 2 ? argv[2] : "newindex.txt", "r"))) {
        fprintf (stderr, "error: file open failed (newindex).\n");
        return 1;
    }

    /* read each line, parse values into float array */
    for (i = 0; i < idx && fgets (buf, MAXC, fp);) {
        if (sscanf (buf, " %f %f", &ftmp, &ftmp2) == 2) {
            array[i][0] = ftmp;
            array[i][1] = ftmp2;
            i++;
        }
        else
            fprintf (stderr, "error: failed to parse values from '%s'.\n",
                     "newindex.txt");
    }
    fclose (fp);

    if (i != idx) { /* validate rows match second.txt */
        fprintf (stderr, "error: mismatch in data between newindex and second.\n");
        return 1;
    }

    /* open/validate "newindex.dat" for output (binary) */
    if (!(fp = fopen (argc > 3 ? argv[3] : "newindex.dat", "w"))) {
        fprintf (stderr, "error: file open failed '%s'.\n",
                 "newindex.dat");
        return 1;
    }

    /* write array to output file in binary using fwrite */
    if (fwrite (array, sizeof *array, idx, fp) != idx)
        fprintf (stderr, "error: file write failed '%s'.\n",
                 "newindex.dat");

    if (fclose (fp))    /* check for error on close (errno set) */
        fprintf (stderr, "error: failure on file close '%s'.\n",
                 "newindex.dat");

    /* open/validate "newindex.dat.txt" for output (formatted text) */
    if (!(fp = fopen (argc > 3 ? argv[3] : "newindex.dat.txt", "w"))) {
        fprintf (stderr, "error: file open failed '%s'.\n",
                 "newindex.dat.txt");
        return 1;
    }

    /* write array to output file in formatted text using fprintf */
    for (i = 0; i < idx; i++)
        fprintf (fp, "%.1f %.1f %.2f\n", 
                array[i][0], array[i][1], array[i][2]);

    if (fclose (fp))    /* check for error on close (errno set) */
        fprintf (stderr, "error: failure on file close '%s'.\n",
                 "newindex.dat.txt");

    /* confirm output values -- open/validate "newindex.dat" */
    if (!(fp = fopen (argc > 3 ? argv[3] : "newindex.dat", "r"))) {
        fprintf (stderr, "error: file open failed '%s'.\n",
                 "newindex.dat");
        return 1;
    }

    float b[MAXF][NCOL] = {{0.0}};  /* read binary data into array */
    if (fread (b, sizeof *b, idx, fp) != idx)
        fprintf (stderr, "error: file write failed '%s'.\n",
                 "newindex.dat");

    fclose (fp);

    printf ("\narray values read from binary file '%s'.\n\n",
            "newindex.dat");
    for (i = 0; i < idx; i++)   /* output data from file */
        printf ("%.1f %.1f %.2f\n", b[i][0], b[i][1], b[i][2]);

    return 0;
}

/* qsort comparison for floats */
int cmpfloat (const void *a, const void *b)
{
    const float *ia = (const float *)a;
    const float *ib = (const float *)b;
    return (ia[NCOL-1] > ib[NCOL-1]) - (ia[NCOL-1] < ib[NCOL-1]);
}

Example Output

示例输出

The program reads the values written to the binary file newindex.dat using fwrite:

该程序使用fwrite读取写入二进制文件newindex.dat的值:

$ ./bin/qsortnewindex2

array values read from binary file 'newindex.dat'.

0.0 0.0 1.20
1.0 0.0 1.20
2.0 0.0 1.20
3.0 0.0 1.20
0.0 1.0 1.40
1.0 1.0 1.40
2.0 1.0 1.42
3.0 1.0 1.48
0.0 2.0 1.50
1.0 2.0 1.50
2.0 2.0 1.52
3.0 2.0 1.54

You can also confirm that the formatted text ouput file was created properly:

您还可以确认格式化的文本输出文件是否已正确创建:

$ cat newindex.dat.txt
0.0 0.0 1.20
1.0 0.0 1.20
2.0 0.0 1.20
3.0 0.0 1.20
0.0 1.0 1.40
1.0 1.0 1.40
2.0 1.0 1.42
3.0 1.0 1.48
0.0 2.0 1.50
1.0 2.0 1.50
2.0 2.0 1.52
3.0 2.0 1.54