実践的データ処理として、複数の項目を持つレコードを ある数値を規準に並べ換えてみよう。
コンピュータでデータ管理をするときには、どんなデータもかならず 同じ項目が含まれるようにする。たとえば、あるデータベースを作るときに
という項目のものを集めると決めたら、全てのデータがこれらの項目だけを 含むようにしなければならない。必要な項目を満たした1件のデータのことを レコードといい、1レコード内の各項目のことをフィールド という。
〜〜〜〜〜〜〜〜〜〜〜〜〜レコード〜〜〜〜〜〜〜〜〜〜〜〜〜 | ||||
公益太郎 | コウエキタロウ | 酒田市飯森山 | 1111 | 最上川 |
フィールド | フィールド | フィールド | フィールド | フィールド |
これらを実際にコンピュータに入力するためのデータ形式としては、
CSV形式 (Comma Separated Value) がもっとも標準的である。
CSV形式は1行が1レコードで、フィールドごとに項目をカンマ(,)
で区切ったものである。
公益太郎,コウエキタロウ,酒田市飯森山,1111,最上川 飯森花子,イイモリハナコ,酒田市飯森山,2222,赤川 酒田三吉,サカタサンキチ,酒田市中町,3333,新井田川
データは全てテキストで記述されるので、たとえ専用のデータベース管理ソ フトウェアが無くても読むことができる。さらに、CSV形式で保存された データはほぼ全てのデータベースソフト、表計算ソフトで扱うことができる。 プログラムでデータ処理をしたあとで、それに基づいたグラフなどを 作成する場合にはCSV形式で処理結果を出力しておくと良い。
以下のようなデータを並べ換えてみよう。
巨人 37 35 1 ヤクルト 37 35 0 横浜 20 52 0 中日 38 34 0 阪神 50 21 1 広島 30 35 0
このデータは、6つのレコードからなり、それぞれ4つのフィールドで構成さ れる。各フィールドは順に、チーム名、勝数、負数、引き分け数となる。 このデータを1行、つまり1レコードずつ読み込んで、各フィールドに切り分けて 読み込む部分は次のようになるだろう。
char buf[100]; FILE *cl; if (NULL == (cl=fopen("celeague.dat", "r"))) { fprintf(stderr, "celeague.dat にデータを置いて下さい\n"); exit(1); } /* ここから読み込み */ while (NULL != fgets(buf, sizeof buf, cl)) { if (3 == sscanf(buf, "%s %d %d", team[n], &win[n], &lose[n])) { /* 3つのデータがちゃんと解析できたら n を1増やす */ n++; } } fclose(cl);
これにより、2次元char型配列 team
にチーム名、
int型配列 win, lose にそれぞれ勝数、負数が入る。
前々回のソートのアルゴリズムを利用して
並べ換えよう。並べ換える規準は勝率にする。データの読み込みによって
win[i], lose[i]
に勝敗数が入っている。ここから勝率を計算す
るには
(float)win[i]/(win[i]+lose[i])
とすれば良い。win, lose
ともにint型の配列なので、
結果が小数となる勝率を計算するときは (float)
によって
float型にキャストすることを忘れないように注意する。
以上のことをふまえて、勝敗表データを勝率の高い順に並べ換えて、 なおかつ結果をCSV形式で出力するプログラムは以下のように書ける。
#include <stdio.h> #include <string.h> #define TL 20 int main() { char buf[100]; int n=0; FILE *cl; char team[6][TL]; /* チーム名 */ char scanfmt[10]; /* sscanf用フォーマット */ int win[6], lose[6]; /* 勝ち 負け */ char temp[TL]; /* 並べ換え用 */ int i, left, x; /* 並べ換え用 */ float r, s; if (NULL == (cl=fopen("celeague.dat", "r"))) { fprintf(stderr, "celeague.dat にデータを置いて下さい\n"); exit(1); } sprintf(scanfmt, "%%%ds %%d %%d", TL-1); /* ここから読み込み */ while (NULL != fgets(buf, sizeof buf, cl)) { if (3 == sscanf(buf, scanfmt, team[n], &win[n], &lose[n])) { /* 3つのデータがちゃんと解析できたら n を1増やす */ n++; } } /* ここから勝率で並べ換え(単純ソート) * 勝率は 勝数/(勝数+負数) */ for (left=0; left<n-1; left++) { for (i=left+1; i<n; i++) { r = (float)win[left]/(win[left]+lose[left]); /* 着目点の勝率 */ s = (float)win[i]/(win[i]+lose[i]); /* 比べる相手の勝率 */ if (r < s) { strlcpy(temp, team[left], TL); /* チーム名の入れ換え */ strlcpy(team[left], team[i], TL); strlcpy(team[i], temp, TL); x = win[left]; /* 勝数の入れ換え */ win[left] = win[i]; win[i] = x; x = lose[left]; /* 負数の入れ換え */ lose[left] = lose[i]; lose[i] = x; } } } /* ここから表示 */ for (i=0; i<n; i++) { r = (float)win[i]/(win[i]+lose[i]); printf("%s,%d,%d,%5.3f\n", team[i], win[i], lose[i], r); } }
celeague.dat
を
同一ディレクトリに置いて実行してみよう。CSV形式で出力される。
% gcc -o celeague celeague.c % ./celeague 阪神,50,21,0.704 中日,38,34,0.528 巨人,37,35,0.514 ヤクルト,37,35,0.514 広島,30,35,0.462 横浜,20,52,0.278