実践的データ処理として、複数の項目を持つレコードを ある数値を規準に並べ換えてみよう。
コンピュータでデータ管理をするときには、どんなデータもかならず 同じ項目が含まれるようにする。たとえば、あるデータベースを作るときに
という項目のものを集めると決めたら、全てのデータがこれらの項目だけを 含むようにしなければならない。必要な項目を満たした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