←検索窓の楽しみ方
  ショッピングモール  掲示板ランキング


【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※返信付き投稿の削除は禁止!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら


 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板1こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧

No.4497

ファイルシャッフル
投稿者---C(2005/08/22 14:50:39)
www.chem.ucla.edu


毎度お世話になります。
過去ログからファイルシャッフルのプログラムを入手しましたが、
これだと全部の行がシャッフルされてしまいます。
どなたか、一行づつシャッフルさせるやり方をご存知の方いらっしゃいますか?
お願いします。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys\stat.h>

int main(void)
{
        FILE    *fin,*fout;
        struct  stat fileinfo ;
        char    infile[40],outfile[40];
        char    wk[300],*bufp,*pp[1000];
        int     i=0,j,r;

        printf("入力ファイル名=");
        gets(infile);
        printf("出力ファイル名=");
        gets(outfile);
        if( (fin=fopen(infile,"r"))==NULL) {
                printf("入力ファイルがオープンできません\n");
                exit(1);
        }
        if( (fout=fopen(outfile,"w"))==NULL) {
                printf("出力ファイルがオープンできません\n");
                exit(1);
        }
        /* ファイル情報の取得 */
        if( stat( infile, &fileinfo ) == -1 ){
                fprintf( stderr,"%sのファイル情報取得に失敗しました\n",infile ) ;
                exit( 1 ) ;
        }
        /* 読み込みエリアの取得 */
        if ( (bufp = (char *)malloc(fileinfo.st_size))==NULL) {
                fprintf( stderr,"mallocエラー\n");
                fclose(fin);
                fclose(fout);
                exit(1);
        }
        /* ファイルの読み込み */
        i = 0;
        pp[0] = bufp;
        while(fgets(wk,256,fin)!=NULL) {
                strcpy(pp[i],wk);
                i++;
                pp[i] = pp[i-1] + strlen(wk) + 1;
        }
        /* ファイルのシャフル */
        j = 0;
        while(j<i) {
                r = rand()%i;
                if (pp[r]!=NULL) {
                        fputs(pp[r],fout);
                        pp[r] = NULL;
                        j++;
                }
        }
        free(bufp);
        fclose(fin);
        fclose(fout);
        return(0);
}




この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:ファイルシャッフル 4500 まきじ 2005/08/22 15:10:01


No.4500

Re:ファイルシャッフル
投稿者---まきじ(2005/08/22 15:10:01)


>これだと全部の行がシャッフルされてしまいます。
>どなたか、一行づつシャッフルさせるやり方をご存知の方いらっしゃいますか?

一行目から順に j 行目と r 行目を入れ替えるプログラムの様ですが、
「一行ずつ」というのは具体的どういう事でしょうか?
また、一行はどういう形式になってるのでしょうか?(CSV とか)


この投稿にコメントする

削除パスワード

No.4501

Re:ファイルシャッフル
投稿者---C(2005/08/22 15:16:17)
www.chem.ucla.edu


返答ありがとうございます。
一行だけシャッフルして出力し、その後、次の一行を出力したいのです。
また、ファイルはCSVでタブ区切りの数値が入っています。


この投稿にコメントする

削除パスワード

No.4502

Re:ファイルシャッフル
投稿者---まきじ(2005/08/22 15:29:00)


>一行だけシャッフルして出力し、その後、次の一行を出力したいのです。
>また、ファイルはCSVでタブ区切りの数値が入っています。

(1) 読み込み用・書き込み用ファイルを開く。
(2) 一行を読み込む。
(3) strtok() あるいは fscanf() などで \t で区切り、配列に格納。
(4) 配列の 0 番目の要素から i 番目と r 番目を入れ替えてシャッフルする。
(5) fprintf() などで、ファイルに出力する。
(6) それぞれのファイルをクローズする。

とりあえず、解る部分をコーディングしてみてください。
解らない部分は、改めて質問してください。

# 過去ログにあったソースを適当に弄ってやろうとする
# ややこしくなるだけなので、一から作る事をお勧めします。


この投稿にコメントする

削除パスワード

No.4503

Re:ファイルシャッフル
投稿者---C(2005/08/22 15:34:34)
www.chem.ucla.edu


ありがとうございます。
C初心者ですが、ウェブなどから以下のものを作りました。
が。。。動きません。
切り貼りしすぎたのでしょうか。。。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<math.h>
#define MAX_MOJISUU 10000
#define N 6


int main(void){

    char filename[256]; 
    char buf[MAX_MOJISUU]; 
    char* p[N+1]; 

    int i, j, k, l; // カウンタ用変数
    int len; // 読み込んだ文字列の長さ

    FILE *fp;
    
      
    // ファイルオープン
    strcpy(filename,"0.csv");
    fp = fopen( filename, "r" );
    if( fp != NULL )
    {
        i = 1;
        while( fgets( buf, MAX_MOJISUU, fp ) 

!= NULL )
        {
          
            len = strlen( buf );
            if( buf[len-1] == '\n' ) buf[len-1] = 

'\0';
            
            // 1行表示
            printf("\n Line %d : %s\n", i++, buf );
            
            // 文字列の分解
            j = 0;
            p[j] = strtok( buf, ",");
            while( p[j] != NULL )
            {
                j++;
                p[j] = strtok( NULL,",");
            }
            
 void genParmutation(int result[], int 

remained[], int n) {

 
    int selected, a;

         
      

    for (a=0; a<=N; a++) {

 int result[1+N], remained[1+N];

        remained[a] = a;

    genParmutation(result, remained, 

N);

    
    
    if (n<0) {
        for (a=0; a<=N; a++)
            putchar(p

[result[a]]);
        putchar('\n');
        return;
    }
    for (a=0; a<=n; a++) {
        selected = remained[a];
        result[n] = selected;
        remained[a] = 

remained[n];
        genParmutation(result, 

remained, n-1);
    
    remained[a] = selected;

}
}
    }

    return;
}






 



   }
    fclose( fp );
    getchar();
    return 0;
}




この投稿にコメントする

削除パスワード

No.4505

Re:ファイルシャッフル
投稿者---まきじ(2005/08/22 16:08:56)


以前と解決できなかったソースですね(^^;
シャッフルするだけなら順列(nPr)は関係ないかと。

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

#define LINE 512
#define TOKEN 10
#define N 32

int line_sep(char (*tokens)[N], char buf[]){

    char *token;
    int i = 0;
    
    token = strtok(buf,"\t");
    while(token){
        strcpy(tokens[i],token);
        token = strtok(NULL,"\t");
        i++;
    }
    
    return i;
}

void line_shuffle(char (*tokens)[N],int col){

    int i, r;
    char tmp[N];
    
    srand((unsigned)time(NULL));
    
    for(i = 0; i < col; i++){
        r = col * rand() / RAND_MAX;
        strcpy(tmp,tokens[i]);
        strcpy(tokens[i],tokens[r]);
        strcpy(tokens[r],tmp);
    }
    
}

void put_line(FILE *fout, char (*tokens)[N],int col){

    int i;
    
    for(i = 0; i < col; i++){
        if(i) fprintf(fout,"%c",'\t');
        fprintf(fout,"%s",tokens[i]);
    }
    fprintf(fout,"%c",'\n');
}

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

    FILE *fin, *fout;
    char buf[LINE];
    char tokens[TOKEN][N];
    int col;
    
    if(argc != 3) return 1;
    if((fin = fopen(argv[1],"r")) == NULL) return 1;
    if((fout = fopen(argv[2],"w")) == NULL) return 1;

    fgets(buf, LINE, fin);  
    while(!feof(fin)){
        if(buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = '\0';
        col = line_sep(tokens,buf);
        line_shuffle(tokens,col);
        put_line(fout,tokens,col);
        fgets(buf, LINE, fin);
    }
    
    fclose(fin);
    fclose(fout);
    return 0;
}



この投稿にコメントする

削除パスワード

No.4506

Re:ファイルシャッフル
投稿者---C(2005/08/22 16:31:11)
www.chem.ucla.edu


丁寧なご返事ありがとうございました。
ところで、どこにファイル名を書けばいいのかわかりません。。。

申し訳ないですが、教えていただけますでしょうか。。。


この投稿にコメントする

削除パスワード

No.4507

Re:ファイルシャッフル
投稿者---まきじ(2005/08/22 16:35:29)


>ところで、どこにファイル名を書けばいいのかわかりません。。。

ソースを読んで、ご自分で考えるなり調べるなりして下さい。


この投稿にコメントする

削除パスワード

No.4508

Re:ファイルシャッフル
投稿者---C(2005/08/22 16:37:29)
www.chem.ucla.edu


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


この投稿にコメントする

削除パスワード

No.4509

Re:ファイルシャッフル
投稿者---とおり(2005/08/22 16:45:25)


>ところで、どこにファイル名を書けばいいのかわかりません。。。

ファイル名は引数によって取得しているようです。

> if((fin = fopen(argv[1],"r")) == NULL) return 1;
> if((fout = fopen(argv[2],"w")) == NULL) return 1;
↑この辺りを理解してみてはいかが?


この投稿にコメントする

削除パスワード

No.4510

Re:ファイルシャッフル
投稿者---C(2005/08/22 17:53:47)
www.chem.ucla.edu


ありがとうございました。
コマンドラインから引数をとるのですね。
感謝します。

ところで、作っていただいたものがコンパイルできましたが、
シャッフルされていないような気がします。。。
(それとも、わたくし何かミスってしまいましたか。。。)


この投稿にコメントする

削除パスワード

No.4511

Re:ファイルシャッフル
投稿者---RAPT(2005/08/22 23:01:26)


>ところで、作っていただいたものがコンパイルできましたが、
>シャッフルされていないような気がします。。。
>(それとも、わたくし何かミスってしまいましたか。。。)

あなたにとって「シャッフルする」の定義は?
どんなデータを与え、どんな結果を期待し、どんな結果になったのか。
その辺りを考察する必要があります。


この投稿にコメントする

削除パスワード

No.4512

Re:ファイルシャッフル
投稿者---まきじ(2005/08/22 23:49:44)


>シャッフルされていないような気がします。。。

タブで区切られていますか?
スペースになってませんか?


この投稿にコメントする

削除パスワード

No.4513

Re:ファイルシャッフル
投稿者---かずま(2005/08/23 02:34:32)


>> シャッフルされていないような気がします。。。

> タブで区切られていますか?
> スペースになってませんか?

プログラムを作ったら、投稿する前にテストをしてみないのですか?

次の内容のファイルを入力してみてください。

123<tab>456<tab>789
123<tab>456<tab>789
123<tab>456<tab>789
123<tab>456<tab>789


srand() の使い方が間違っています。


この投稿にコメントする

削除パスワード

No.4518

Re:ファイルシャッフル
投稿者---まきじ(2005/08/23 09:04:39)


>123<tab>456<tab>789
>123<tab>456<tab>789
>123<tab>456<tab>789
>123<tab>456<tab>789

そういう事だったのか・・・
全行同じデータでテストしてませんでした。

>srand() の使い方が間違っています。

>C さん
srand((unsigned)time(NULL)) を main() の fopen() の後に記述してください。


この投稿にコメントする

削除パスワード

No.4521

Re:ファイルシャッフル
投稿者---C(2005/08/23 13:29:28)
www.chem.ucla.edu


>>123<tab>456<tab>789
>>123<tab>456<tab>789
>>123<tab>456<tab>789
>>123<tab>456<tab>789

まきじさん、ありがとうございました。
でも。。。以下のソースでも上記のように行ごとにシャッフルできません。


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

#define LINE 512
#define TOKEN 10
#define N 32

int line_sep(char (*tokens)[N], char buf[]){

    char *token;
    int i = 0;
    
    token = strtok(buf,"\t");
    while(token){
        strcpy(tokens[i],token);
        token = strtok(NULL,"\t");
        i++;
    }
    
    return i;
}

void line_shuffle(char (*tokens)[N],int col){

    int i, r;
    char tmp[N];
    
    srand((unsigned)time(NULL));
    
    for(i = 0; i < col; i++){
        r = col * rand() / RAND_MAX;
        strcpy(tmp,tokens[i]);
        strcpy(tokens[i],tokens[r]);
        strcpy(tokens[r],tmp);
    }
    
}

void put_line(FILE *fout, char (*tokens)

[N],int col){

    int i;
    
    for(i = 0; i < col; i++){
        if(i) fprintf(fout,"%c",'\t');
        fprintf(fout,"%s",tokens[i]);
    }
    fprintf(fout,"%c",'\n');
}

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

    FILE *fin, *fout;
    char buf[LINE];
    char tokens[TOKEN][N];
    int col;
    
    if(argc != 3) return 1;
    if((fin = fopen(argv[1],"r")) == NULL) 

return 1;
    if((fout = fopen(argv[2],"w")) == NULL) 

return 1;
srand((unsigned)time(NULL));
    fgets(buf, LINE, fin);  
    while(!feof(fin)){
        if(buf[strlen(buf) - 1] == '\n') buf

[strlen(buf) - 1] = '\0';
        col = line_sep(tokens,buf);
        line_shuffle(tokens,col);
        put_line(fout,tokens,col);
        fgets(buf, LINE, fin);
    }
    
    fclose(fin);
    fclose(fout);
    return 0;
}




この投稿にコメントする

削除パスワード

No.4522

Re:ファイルシャッフル
投稿者---まきじ(2005/08/23 14:11:02)


>でも。。。以下のソースでも上記のように行ごとにシャッフルできません。

111 222 333 444 555
111 222 333 444 555
111 222 333 444 555
111 222 333 444 555
111 222 333 444 555

というデータに対して実行すると

222 444 333 555 111
555 444 222 111 333
222 333 111 444 555
333 444 111 555 222
333 444 111 222 555

となりますが、これでは駄目なのですか?


この投稿にコメントする

削除パスワード

No.4523

Re:ファイルシャッフル
投稿者---RAPT(2005/08/23 14:16:19)


WindowsXPsp2/VC++6sp6/ConsoleApp/C
当方の環境でこのコードをコンパイル・実行したらシャッフルされてましたよ?
但し、各行とも先頭行と同じパターンでしたが。

もしかして「たまたま」シャッフルされていないように「見える」結果が
出て、しかも1回だけしか検証していないのでは?
時刻ベースで乱数表を初期化しているので、何回も実行してみないと、
正しい評価はできません。


各行とも先頭行と同じパターンになるのは、下記のコードを修正すれば
改善されます。

> void line_shuffle(char (*tokens)[N],int col)
の
> srand((unsigned)time(NULL));
を削除してください。


srand()はプログラム中で唯1回だけ呼び出されるようにすべきです。
今回の例で行くと、line_shuffle()で毎回呼び出されることにより、
現在時刻を基数として乱数表が初期化されますが、件数が少ないと
処理は一瞬で終わるため、(unsigned)time(NULL) の結果が同一と
なったのでしょう。

テストに使用したデータ:
1<tab>2<tab>3<tab>4<tab>5<tab>6<tab>7<tab>8<tab>9
1<tab>2<tab>3<tab>4<tab>5<tab>6<tab>7<tab>8<tab>9
1<tab>2<tab>3<tab>4<tab>5<tab>6<tab>7<tab>8<tab>9
1<tab>2<tab>3<tab>4<tab>5<tab>6<tab>7<tab>8<tab>9



この投稿にコメントする

削除パスワード

No.4527

Re:ファイルシャッフル
投稿者---C(2005/08/23 15:15:39)
www.chem.ucla.edu




> void line_shuffle(char (*tokens)[N],int col)

> srand((unsigned)time(NULL));
を削除しましたが、やはり先頭行と同じ結果がでます。。。

もし、私が間違っていたら、無視してください。。。





この投稿にコメントする

削除パスワード

No.4528

Re:ファイルシャッフル
投稿者---まきじ(2005/08/23 15:19:54)


>> srand((unsigned)time(NULL));
>を削除しましたが、やはり先頭行と同じ結果がでます。。。

推測ですが、コマンドライン引数にファイル名 二つ指定してますか?
シャッフルしたいデータが記述されている読み込み用 と
シャッフルしたデータが出力される書き込み用


この投稿にコメントする

削除パスワード

No.4530

Re:ファイルシャッフル
投稿者---C(2005/08/23 15:28:30)
www.chem.ucla.edu


はい。
取り込みファイルは

3<tab>4<tab>5<tab>1<tab>2<tab>
3<tab>4<tab>5<tab>1<tab>2<tab>
3<tab>4<tab>5<tab>1<tab>2<tab>

結果は

4<tab>5<tab>1<tab>2<tab>3<tab>
4<tab>5<tab>1<tab>2<tab>3<tab>
4<tab>5<tab>1<tab>2<tab>3<tab>

でした。

ソースは以下のとうりです。


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

#define LINE 512
#define TOKEN 10
#define N 32

int line_sep(char (*tokens)[N], char buf[]){

    char *token;
    int i = 0;
    
    token = strtok(buf,"\t");
    while(token){
        strcpy(tokens[i],token);
        token = strtok(NULL,"\t");
        i++;
    }
    
    return i;
}

void line_shuffle(char (*tokens)[N],int col){

    int i, r;
    char tmp[N];
   
    
    for(i = 0; i < col; i++){

   srand((unsigned)time(NULL));
        r = col * rand() / RAND_MAX;
        strcpy(tmp,tokens[i]);
        strcpy(tokens[i],tokens[r]);
        strcpy(tokens[r],tmp);
    }
    
}

void put_line(FILE *fout, char (*tokens)

[N],int col){

    int i;
    
    for(i = 0; i < col; i++){
        if(i) fprintf(fout,"%c",'\t');
        fprintf(fout,"%s",tokens[i]);
    }
    fprintf(fout,"%c",'\n');
}

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

    FILE *fin, *fout;
    char buf[LINE];
    char tokens[TOKEN][N];
    int col;
    
    if(argc != 3) return 1;
    if((fin = fopen(argv[1],"r")) == NULL) 

return 1;
    if((fout = fopen(argv[2],"w")) == NULL) 

return 1;

    fgets(buf, LINE, fin);  
    while(!feof(fin)){
        if(buf[strlen(buf) - 1] == '\n') buf

[strlen(buf) - 1] = '\0';
        col = line_sep(tokens,buf);
        line_shuffle(tokens,col);
        put_line(fout,tokens,col);
        fgets(buf, LINE, fin);

    }
    
    fclose(fin);
    fclose(fout);
    return 0;
}







この投稿にコメントする

削除パスワード

No.4531

Re:ファイルシャッフル
投稿者---まきじ(2005/08/23 15:36:10)


4523 の RAPT さんのレスをもう一度良く読みましょう。


この投稿にコメントする

削除パスワード

No.4525

Re:ファイルシャッフル
投稿者---まきじ(2005/08/23 14:20:01)


説明不足でした、RAPTさんの仰る様に、
line_shuffle() から srand() は消してください。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧




掲示板提供:Real Integrity