Membaca file teks dan mengurutkan dua array

Saya memiliki "Temp.dat" dengan 200 baris yang terlihat seperti ini:

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

Saya mencoba membaca setiap baris dan menyimpan setiap kolom data ke dalam array terpisah dengan kode berikut:

#include <stdio.h>
#include <stdlib.h>
#define MAX 200

int main(){

  double x[MAX], y[MAX];
  double a, b;
  int m = 0;
  FILE* file; 
  file = fopen("Temp.dat", "r");
  if ( file != NULL ){
      /* Read the two columns. */
      while(fscanf(file, "%d %d", &a, &b) == 2)
      { x[m] = a;
        y[m] = b;
        m++;
      }
  }
  printf("%d %d\n", x[4], y[1]); # Test the stored inputs of the two arrays
  return(0);
}    

Saat saya mencoba mencetak hasilnya, hasilnya 1 13258992, bukan 0.165453 0. Saya tidak mengerti dari mana ia mendapatkan pasangan 1 13258992, karena saya pikir baris fscanf(file, "%d %d", &a, &b) == 2 melakukan apa yang seharusnya dilakukan: menelusuri setiap baris file Temp.dat dan membaca dua bilangan bulat double-type, kemudian disimpan dalam dua array x[MAX] dan `y[MAX ]. Oleh karena itu, adakah yang bisa membantu saya memperbaiki masalah ini?

Pertanyaan lain: Setelah menyimpan dua kolom di atas dalam dua larik x[MAX] dan y[MAX], saya ingin mengurutkan kedua larik tersebut dalam urutan menaik berdasarkan nilai pada larik pertama x[MAX]. Ini akan terlihat seperti:

    0.060493 1
    0.07085  1
    0.122609 0
    0.125379 1
    0.131486 1
    0.165453 1
    0.373227 1
    0.454202 1
    0.867477 0

Bagaimana saya bisa melakukan rutinitas sorting ini di C, karena cukup sulit untuk mengatur elemen di y[MAX] mengikuti urutan elemen terkait di x[MAX]?


person user177196    schedule 19.02.2018    source sumber
comment
@Pablo: Terima kasih atas bantuan Anda. Saya menambahkan kondisi di while, dan mengubah %d menjadi %lf, tetapi hasilnya masih salah. Sekarang ini memberi saya -1 34902256 untuk x[4] y[1] yang sama. Bisakah Anda memberi saya beberapa petunjuk tentang cara mengurutkan array kedua saat saya menukar setiap elemen dari array pertama?   -  person user177196    schedule 19.02.2018
comment
Saya menghapus komentar saya dan mempostingnya sebagai jawaban. Anda mengalami kesalahan yang sama pada panggilan printf. Lihat jawaban saya.   -  person Pablo    schedule 19.02.2018


Jawaban (3)


Anda dapat mendeklarasikan struktur dengan x dan y, sehingga kedua nilai terikat bersama, x dan y akan menjaga hubungannya ketika elemen array ditukar selama pengurutan. Contoh:

struct data_t
{
    double x;
    int y;
};

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

int main(void) 
{
    struct data_t data[MAX];
    FILE* file = fopen("Temp.dat", "r");
    int count = 0;
    while(fscanf(file, "%lf %d", &data[count].x, &data[count].y) == 2)
    {
        count++;
        if (count == MAX)
            break;
    }

    qsort(data, count, sizeof(struct data_t), compare);
    for(int i = 0; i < count; i++)
        printf("%lf %d\n", data[i].x, data[i].y);
    return 0;
}

Gunakan %lf untuk nilai double, atau gunakan %f untuk float , seperti yang ditunjukkan pada jawaban lain

Tentang fungsi perbandingan, katakanlah Anda memiliki nilai berikut di data Anda:

0.060493 1
0.060493 5
0.060493 2

Dalam hal ini nilai x dari elemen pertama sama dengan nilai x dari elemen lainnya. Jika Anda hanya menguji m->x > n->x maka penyortiran tidak terjadi. Jadi Anda ingin membandingkan m->y > n->y jika x sama.

qsort adalah fungsi C standar. Ia tidak mengetahui tipe data Anda, kami harus memberi tahu tentang tipe datanya. Itu dilakukan di dalam fungsi perbandingan yang menerima pointer a dan b, kita tahu ini adalah pointer ke elemen dalam array data, jadi itulah alasan di balik konversi.

Kumpulan data dapat berisi hingga 200 item karena kami mendeklarasikannya sebagai struct data_t data[MAX]; dengan MAX adalah 200.


Edit 3 ******
Bekerja dengan array, deklarasikan array:

double arr[MAX + 1][8]

Perhatikan bahwa indeks pertama array adalah baris dari 0 hingga MAX. Ini diatur sedemikian rupa sehingga dapat diurutkan nanti. Sekarang kita dapat membaca file langsung ke dalam array, dan mengurutkan array (tidak memerlukan struktur). Pastikan Anda tidak mencampuradukkannya dengan solusi lama yang memiliki arr[8][MAX + 1]

int compare_2d_array(const void *pa, const void *pb)
{
    double a = *(double*)pa;
    double b = *(double*)pb;
    return a > b;
}

int main(void)
{
    //array with MAX + 1 rows, and 8 columns, initialized to zero
    double arr[MAX + 1][8] = { 0 };
    FILE* file = fopen("temp.dat", "r");
    int count = 0;
    while(fscanf(file, "%lf %lf", &arr[count][0], &arr[count][1]) == 2)
    {
        count++;
        if(count == MAX) break;
    }

    qsort(arr, count, sizeof(arr[0]), compare_2d_array);

    //arr[0] and arr[1] are ready, now set up the other columns:
    for(int i = 0; i < count; i++)
    {
        //make modifications to other columns
        arr[i][2] = i ? arr[i - 1][0] : 0;
        arr[i][3] = arr[i][0];
        arr[i + 1][4] = i + 1;

        printf("%.6lf %.0lf %.6lf %.6lf %.0lf\n", 
                    arr[i][0], arr[i][1], arr[i][2], arr[i][3], arr[i][4]);
    }
    return 0;
}
person Barmak Shemirani    schedule 19.02.2018
comment
Saya mencoba kode Anda dan berfungsi luar biasa dengan kumpulan data!! Terima kasih banyak atas bantuanmu. Namun saya punya beberapa pertanyaan: dapatkah Anda membantu menjelaskan kepada saya mengapa pengembalian m->y > n->y? dalam fungsi compare() Anda? Juga, deklarasi pointer const struct data_t *m = a membantu?? Apakah struct data_t = kumpulan data dengan $200$ pasang (x,y)? - person user177196; 19.02.2018
comment
Terima kasih banyak atas bantuan Anda, karena sudah cukup jelas!! Saya punya pertanyaan lain: dari dua kolom, asumsikan kolom pertama menunjukkan waktu $T$, dan kolom kedua berarti 1= Death occurs dan 0 = Censor occurs. Saya ingin membuat dua array, yang menyimpan kuantitas yang dihitung berikut: array pertama menyimpan jumlah orang yang hidup dan tidak disensor di antara dua berturut-turut periode waktu, dan array kedua menyimpan jumlah kematian yang terjadi selama periode waktu yang sama. Bisakah Anda membantu bagaimana saya harus melakukan ini dengan loop int array[MAX] dan for? - person user177196; 19.02.2018
comment
Saya mencoba for (int i = 0; i<m; i++){sum[i] = MAX - i;} tetapi kemudian printf("%d", &sum[4]) tidak menghasilkan apa pun untuk saya. Tidak yakin mengapa tidak disimpan di array sum[]? Selain itu, saya ingin menyimpan kolom pertama ke dalam array di mana setiap elemen = periode waktu berturut-turut yang titik akhirnya sesuai dengan 1 di kolom kedua (jadi, tidak ada titik akhir yang sesuai dengan 0). Tapi saya bingung bagaimana menulis kondisi rumit seperti ini. Bisakah Anda memberikan bantuan? - person user177196; 19.02.2018
comment
Saya mencobanya printf("%d", sum[4]) juga, tetapi masih tidak mencetak apa pun (walaupun tidak ada pesan kesalahan yang terjadi). Bagaimanapun, bisakah Anda membantu menunjukkan kepada saya cara menyimpan periode waktu yang berurutan dalam array yang memiliki titik akhir sama dengan 1 di kolom ke-2? Misalnya array dengan elemen [0, 0.060493), [0.060493, 0.07085), [0.07085, 0.122609), dll. Saya rasa saya mungkin harus menggunakan array 2 dimensi, salah satunya untuk menyimpan periode waktu, yang lain untuk menyimpan hasil komputasi, dan indeks keduanya sama persis ( yaitu, untuk t\in [0, 0.060493), kita punya result 1) - person user177196; 19.02.2018
comment
Mari kita melanjutkan diskusi ini dalam chat. - person user177196; 19.02.2018
comment
Lihat (Edit 3 ****), sertakan itu dalam pertanyaan baru Anda bersama dengan contoh masukan dan keluaran yang diharapkan - person Barmak Shemirani; 20.02.2018
comment
jika saya menambahkan dua kolom tambahan ke dalam dataset asli, tahukah Anda cara menyusun elemen di kedua kolom tersebut berdasarkan hasil pengurutan kolom pertama?? Apakah fungsi Anda compare(), tetapi dengan 2 pointer tambahan dalam pengaturan input, masih berfungsi (yaitu,` int bandingkan(const void *a, const void *b, const void *c, const void *d)`)? - person user177196; 01.03.2018
comment
bisakah Anda membantu saya dengan pertanyaan saya di komentar di atas? Saya memodifikasi kumpulan data asli untuk kejelasan. Saya mencoba menulis int compare_4d_array(const void *a, const void *b, const void *c, const void *d), tetapi gagal berfungsi dengan baik. - person user177196; 08.03.2018
comment
Saya tidak bermaksud mengurutkan apa pun, kecuali mengubah baris entri yang sesuai di kolom 2 dan 3 di atas menjadi yang benar setelah mengurutkan berdasarkan kolom 0 dan 1 di atas, seperti yang Anda sajikan. Tapi saya akan memulai pertanyaan baru. - person user177196; 09.03.2018
comment
Saya bingung. Komentar saya sebelumnya tidak masuk akal. Anda masih memiliki satu larik 2 hari. Tidak ada susunan 4-d. Pertahankan fungsi proc sebagai compare_2d_array(const void *element1, const void *element2) - person Barmak Shemirani; 09.03.2018
comment
Anda dapat mengajukan pertanyaan baru berdasarkan pengurutan array 2 hari, berdasarkan 2 kolom atau lebih. Juga, di pertanyaan lain saya menunjukkan cara mengurutkan struktur, itu adalah konsep serupa. - person Barmak Shemirani; 09.03.2018
comment
terima kasih banyak atas bantuan Anda. Bisakah Anda membagikan tautan ke pertanyaan itu kepada saya? - person user177196; 09.03.2018
comment
Saya memposting yang baru! stackoverflow .com/questions/49183054/. Tolong bantu. - person user177196; 09.03.2018

Sebagai permulaan, coba:

double a;
int b;

...

fscanf(file, "%f %d", &a, &b)

Anda menginisialisasi a dan b sebagai tipe ganda tetapi Anda membaca bilangan bulat (%d) dari file copy.dat. b adalah nilai int jadi biarkan %d di fscanf dan ubah inisialisasi.

person Tukanuk    schedule 19.02.2018
comment
Aku mengerti sekarang. Terima kasih banyak. Bisakah Anda membantu dengan fungsi pengurutan? - person user177196; 19.02.2018
comment
Lakukan pencarian untuk bubble sort. Ini bukan jenis yang paling efisien atau tercantik tetapi mudah untuk dikodekan dan pada dasarnya akan bekerja melalui 200 nilai secara instan. - person Tukanuk; 19.02.2018
comment
Agar larik y mengikuti jenis larik x, terapkan logika pencarian ke larik x saja, tetapi tukar larik x dan y secara bersamaan. - person Tukanuk; 19.02.2018

Pertama tambahkan && m < MAX pada kondisi while, agar buffer tidak meluap.

scanf mengharapkan dengan %d sebuah penunjuk ke int, bukan ke double dan itu akan mengurai konten sebagai bilangan bulat. Anda harus menggunakan %lf untuk mengurai doubles. Hal yang sama berlaku untuk panggilan printf:

while(fscanf(file, "%lf %lf", &a, &b) == 2 && m < MAX)
    ...

...

printf("%lf %lf\n", x[4], y[1]);

saya mendapat

0.070850 0.000000

yang merupakan baris kelima dari file dat Anda (bukan baris keempat, indeks array dimulai dengan 0, bukan 1).

Adapun pertanyaan Anda yang lain:

Saya khawatir Anda harus menulis fungsi pengurutan Anda sendiri.

person Pablo    schedule 19.02.2018
comment
Saya mendapat bagian pertama sekarang!! Terima kasih banyak atas bantuan Anda, Pablo. Saya menggunakan OS Mac. Bisakah Anda membantu menunjukkan kepada saya cara melakukan ini dengan qsort_r? - person user177196; 19.02.2018
comment
Seperti yang saya katakan, qsort_r adalah ekstensi GNU dari kompiler GCC, Anda perlu mengkompilasinya dengan kompiler GCC. Maaf membingungkan Anda, tetapi bahkan qsort_r tidak akan membantu di sini, karena Anda perlu mengetahui indeks mana dalam array yang dibandingkan dan qsort meneruskan nilainya, bukan indeksnya. Saya khawatir Anda harus menulis fungsi penyortiran Anda sendiri. - person Pablo; 19.02.2018