ページ 11

ファイル内容のソート

Posted: 2007年7月04日(水) 16:54
by @とんぷぅ~

Seseki.txtというファイルに、以下のように試験の成績が入っている。
件数は、最大100件とする。

学籍番号 性    名   性別   国語 数学 理科 社会 英語
0001 Fukusima Taro M 60 70 90 30 50
0002 Fukuda Hanako F 80 50 90 70 40
0003
:
:

このファイルを読み、以下の処理を施して科目別のファイルに結果を書き込むプログラムを作成せよ。
・処理
・科目ごとに成績順に並び変える。
 成績が同じ場合、学籍番号順に並べる。

・科目ごとの平均点を求める。
 平均点は、全体の平均、男の平均、女の平均、それぞれを求める。

・個人ごとの総合点を求め、総合点順に並べ変える。
 成績が同じ場合、学籍番号順に並べる。

・総合点の平均を求める。
 平均点は、全体の平均、男の平均、女の平均、それぞれを求める。

書き込むファイルは全部で6個のファイルである。
・国語の成績表 Kokugo.txt
・数学の成績表 Suugaku.txt
・理科の成績表 Rika.txt
・社会の成績表 Syakai.txt
・英語の成績表 Eigo.txt
・総合の成績表 Sougou.txt

書き込むファイルのフォーマットは以下の通り。

成績表  国語
平均点     
男の平均点
女の平均点
順位 学籍番号 性 名   性別      得点
    1   0002 Fukuda Hanako F 80
2 0001 Fukushima Taro M 60

というのが今回の課題なんですが、ハッキリ言って殆ど分かりません(涙)
まずファイルをオープンして、ファイル内容をソートするのが分かりません。
どのようにすればよいのでしょうか?

自分もよく分からないまま作成しているので意味不明なんですが、
ソートとファイルオープンまではやってみました。これから具体的にどうすれば
いいのかご教授下さい。構造体も初めて使ったので変数宣言で、
足りない部分やおかしい部分があったら指摘して下さい。
よろしくお願いします。

Re:ファイル内容のソート

Posted: 2007年7月04日(水) 17:22
by toyo
まずファイルからデータの読み込みですが
最大100件ということならSCORE構造体の配列を100個作っておいて
それにファイルから読み込んだデータをループでEOFになるまで代入していけばどうでしょうか
fgets( )で文字列として1行読んでscanf( )で代入するか最初からfscanf( )で代入も出来ます。

Re:ファイル内容のソート

Posted: 2007年7月04日(水) 17:34
by toyo
構造体がファイルと違ってますね
性別のところは姓のことでしょうか
typedef struct SCORE 
{	
	int bangou;		//	学籍番号
	char sei[20];	//	性
	char name[10];	//	名前
	char sex;	//	性別
	int Japanese;	//	国語
	int math;		//	数学
	int science;	//	理科
	int social;		//	社会
	int english;	//	英語
} SCORE;
あと読み込むときにカウンタをつけて件数を保存しておくといいですね

Re:ファイル内容のソート

Posted: 2007年7月04日(水) 18:32
by @とんぷぅ~
toyoさん初めまして。

丁寧な説明ありがとうございます。
typedef struct SCORE 
{	
	int  number;	//	学籍番号
	char sei[20];	//	性別
	char name[10];	//	名前
	int  japanese;	//	国語
	int  math;	//	数学
	int  science;	//	理科
	int  social;	//	社会
	int  english;	//	英語
}; 
struct SCORE student[100];
一応上記の様にSCORE構造体の配列を100個ほど作りました。

>それにファイルから読み込んだデータをループでEOFになるまで代入していけばどうでしょうか
 fgets( )で文字列として1行読んでscanf( )で代入するか最初からfscanf( )で代入も出来ます。

すみません。知識不足で理解できていないんですが、こういうことでしょうか?
while ((c = fgetc(fp)) != EOF)
	{
		for ( i = 0; i < 100; i++ )
		{
			fscanf(fp, "%d", &student.number);
			fscanf(fp, "%s", &student.sei);
			fscanf(fp, "%s", &student.name);
			fscanf(fp, "%d", &student.japanese);
			fscanf(fp, "%d", &student.math);
			fscanf(fp, "%d", &student.science);
			fscanf(fp, "%d", &student.social);
			fscanf(fp, "%d", &student.english);
        }
}

たぶん違うと思いますが。。。

Re:ファイル内容のソート

Posted: 2007年7月04日(水) 20:47
by とよtoyo
エラー処理等考えると1行ずつ読み込んでsscanfしたほうがいいかもしれません
データを読み込んで確認表示するところまで
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define ARRAY_SIZE 100

typedef struct SCORE 
{	
	int bangou;		//	学籍番号
	char sei[20];	//	性
	char name[20];	//	名
	char sex;		//	性別
	int japanese;	//	国語
	int math;		//	数学
	int science;	//	理科
	int social;		//	社会
	int english;	//	英語
};

struct SCORE student[ARRAY_SIZE];

int main(void)
{
	FILE *fp;
	char buf[256];
	int count = 0;
	int n, i;
	
	if ((fp = fopen("Seiseki.txt", "rt")) == NULL) {
		fprintf(stderr, "The file doesn't open it\n");
		return 1;
	}
	while (fgets(buf, 256, fp) != NULL)
	{
		n = sscanf(buf, "%d %s %s %c %d %d %d %d %d",
			&student[count].bangou, student[count].sei, student[count].name, &student[count].sex,
			&student[count].japanese, &student[count].math, &student[count].science, &student[count].social, &student[count].english
		);
		if (n != 9)
		{
			fprintf(stderr, "scanf error in line %d\n", count + 1);
			return 1;
		}
		count++;
	}
	fclose(fp);
	for (i = 0; i < count; i++)
	{
		printf("%d %s %s %c %d %d %d %d %d\n",
			student.bangou, student.sei, student.name, student.sex,
			student.japanese, student.math, student.science, student.social, student.english
		);
	}

	return 0;
}

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 00:18
by @とんぷぅ~
とよtoyoさん初めまして。もしかしてtoyoさんですか???

>エラー処理等考えると1行ずつ読み込んでsscanfしたほうがいいかもしれません
 ご指摘ありがとうございます。確かにエラーチェック
 が可能なので上記関数を使う方がいいかもしれませんね。

明日、早速コンパイルして動かしてみます。レスありがとうございました。

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 11:52
by @とんぷぅ~
ソートなんですが、バブルソートの関数を作成して引数を渡す場合
構造体の各メンバを指定してやればいいのでしょうか?

・例えば科目ごとに成績順に並び替える場合
 国語なら国語、数学なら数学という感じでいいんでしょうか?

分かりにくくてすみません。

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 12:28
by toyo
もちろんいろいろ方法があるのでこれが正解というものはありませんが
バブルソート関数の引数にソートキーの項目を増やす方法もありますし
int Bsort(SCORE x[/url], int n, int key){ }
ソート用の配列にキーデータをコピーして関数を呼び出す方法も
int Bsort(int x[/url], int n) { }

	for (i = 0; i < count; i++)
	{
		x = student.japanese;
	}
	Bsort(x, count);

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 13:49
by @とんぷぅ~
toyoさん。レスありがとうございます。

科目ごとに並べ替えなんですが
x = student.japanese;
x = student.math;
とすると、最初のiの値が上書きされてしまうのを防ぐため
関数の引き数を増やすということなんでしょうか?

う~ん。どのように行えばいいのか全く分かりません(泣)
実際同じ場合等はどのようにすればよいのでしょうか?
質問ばかりで申し訳ないです。

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 14:38
by toyo
一応こんな風に書いてみました
科目別には繰り返しでいいですが合計点の時はキーに各科目の合計を入れると良いでしょう

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 16:11
by @とんぷぅ~
toyoさん。レスありがとうございます。

>科目別には繰り返しでいいですが
 英語なら英語で変数を用意して以下のようにすればよいでしょうか?

for (s = 0; s < count; s++)
{
key = student.english;
}

>合計点の時はキーに各科目の合計を入れる
 合計と平均の関数を作成して求めたいのですが、ファイルに入力されている
 点数を拾うにはどうすればよいのでしょうか?
 具体的には // 合計点、男女別の点数も処理の部分です。

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 16:29
by toyo
国語の処理を全部終わらせて次の科目に移るので変数は同じものを使いまわします。

// 国語
for (i = 0; i < count; i++)
{
key = student.japanese;
}
Bsort(key, count);
// ファイル書き込み

// 数学
for (i = 0; i < count; i++)
{
key = student.math;
}
Bsort(key, count);
// ファイル書き込み
/*
他の科目繰り返し
*/
// 合計
for (i = 0; i < count; i++)
{
key = student.japanese+student.math
+student.science+student.social+student.english;
}
Bsort(key, count);
// ファイル書き込み

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 17:20
by @とんぷぅ~
toyoさんレスありがとうございます。

一応コーディングしてみましたが、後は平均点なんですが
処理が多くて混乱しています。どのようにすればよいでしょうか?

ちなみに書き込みフォーマットなんですが、

成績表 国語
平均点        64.8
男の平均点 58.9
女の平均点      72.1
順位 学籍番号 性 名 性別 得点
1 0002 Fukuda Hanako F 80
2 0001 Fukushima Taro M 60
:
:

のように出力するのですが、なかなか上手くいきません。
ご教授お願いします。何度もすみません。

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 17:22
by @とんぷぅ~
ちなみに上の男の平均だけずれてますが、64.8と72.1の間にきます。
順位から下もずれてますが。。。(汗)見ずらくてすみません。

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 18:00
by toyo
国語の部分だけ平均処理つけてみました
ファイル書き込みは1行ずつにしたほうが見やすいと思いますが

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 18:34
by @とんぷぅ~
レスありがとうございます。

フォーマットのことなんですが、性と名の部分は
性    名
Fukuda  Hanako
Fukusima Taro

としたいのですがここが上手くいきません。
個人個人で長さが違うのでどうすればよいのでしょうか? 

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 19:01
by toyo
そうですねタブやスペースでいろいろ調節するしかないですね
fprintf(fp, "順位 学籍番号\t性                  名                   性別\t得点\n");
	for (i = 0; i < count; i++)
	{
		fprintf(fp, "%3d     %04d\t%-20s%-20s %c\t%3d\n",
			i + 1, student.bangou, student.sei, student.name, student.sex, key
		);
	}

Re:ファイル内容のソート

Posted: 2007年7月05日(木) 19:03
by toyo
性じゃなくて姓ですね

Re:ファイル内容のソート

Posted: 2007年7月06日(金) 01:01
by @とんぷぅ~
toyoさんレスありがとうございます。

やはりスペースで調整していくしかなさそうですね。
ただ一人一人苗字と名前の長さが違うのがネックですね。

一応国語だけはそれっぽくしてみました。
指摘ありましたらよろしくお願いします。

Re:ファイル内容のソート

Posted: 2007年7月06日(金) 11:47
by @とんぷぅ~
連続レスすみません。

出力フォーマットなんですが、格項目の下に先頭文字を配置したい
んですが、スペースで揃えると、名前がそれぞれ違う長さなので
その部分を揃えても性別や各教科の部分でズレが生じてしまいます。


Fukusima


Taro

性別
M

という感じにしたいです。今はバラバラなのでどうにかしたいのですが、
どんな方法があるでしょうか?

Re:ファイル内容のソート

Posted: 2007年7月06日(金) 13:11
by toyo
%-20sのように文字数決めて左揃えでどうでしょう

fprintf(fp, "順位 学籍番号 姓 名 性別 得点\n");
fprintf(fp, "%3d %04d %-20s%-20s%c %3d\n",

Re:ファイル内容のソート

Posted: 2007年7月06日(金) 13:57
by @とんぷぅ~
toyoさん。レスありがとうございます。
%-は新たな発見でした。本当にありがとうございます。

後は頑張って関数化してみます。

Re:ファイル内容のソート

Posted: 2007年7月06日(金) 18:37
by @とんぷぅ~
連レス失礼します。

少しずつ関数化を始めたのですが、書き込みの部分が
繰り返し起こっているので、1回にしたいのですが、
これは構造体の部分を繰り返す(?)様な関数を作ればよいのでしょうか?
一応ソース載せておきます。

---ヘッダ部分---
/*	マクロ	*/
#define ARRAY_SIZE 100		//	配列サイズ	

#define ERROR_CODE_OPEN_ERROR  "The file doesn't open it"			//	ファイルオープンエラー
#define ERROR_CODE_SCANF_ERROR "Scanf error in line"				//	入力した個数が違う場合のエラー	
#define ERROR_CODE_SEX_ERROR   "Unkown sex in line"					//	性別が異なる (M, F) 以外の場合のエラー
#define ERROR_CODE_WRITE_ERROR "The file cannot write and it do"	//	ファイル書き込みエラー


/*	プロトタイプ宣言  */
int Bsort(int[/url], int);		//	バブルソート


/*	構造体の宣言  */
typedef struct
{	
	int  bangou;		//	学籍番号
	char sei[20];		//	姓
	char name[20];		//	名
	char sex;			//	性別
	int  japanese;		//	国語
	int  math;			//	数学
	int  science;		//	理科
	int  social;		//	社会
	int  english;		//	英語
} SCORE;


/*	構造体の配列studentの宣言  */
SCORE student[ARRAY_SIZE];
---バブルソート部分---
#include "Test.h"

int Bsort(int x[/url], int n)
{
	int i, j, tmp;
	SCORE stmp;
	
	//	比較作業を止める位置の添字
	for (i = 0; i < n - 1; i++)	
	{
		//	比較対象となる要素の添字
		for (j = i + 1; j < n; j++) 
		{
			//	目的の順番の逆になっているか
			if ( x[j] > x ) 
			{
				//	逆になっていたら、並び替えを行う
				tmp  = x[j];
				x[j] = x;
				x = tmp;
				stmp = student[j];
				student[j] = student;
				student = stmp;
			}
			else if (x == x[j] && student.bangou > student[j].bangou)
			{
				//	学籍番号順
				tmp  = x[j];
				x[j] = x;
				x = tmp;
				stmp = student[j];
				student[j] = student;
				student[i] = stmp;
			}
		}
	}
	return 0;
}

Re:ファイル内容のソート

Posted: 2007年7月10日(火) 10:20
by @とんぷぅ~
無事解決できました。

toyoさん。ありがとうございました。