- ベストアンサー
効率的なデータ統合プログラム作成とは?
- 2つのデータを統合するプログラムをperlで作成しています。
- 最終データが必要な際に、2つのデータを読み込みながら更新処理を行っています。
- しかし、データ件数が多くなると非効率になり動作しなくなる問題があります。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
最初に確認ですが (1) $namefile: 名前データ→最終データに書き換え、クラスデータの無いものはそのまま $classfile: クラスデータ→名前データにある行は削除 別のファイルに出力するのではないですね? (2) 一つ目の値で統合するのですね?この値は重複してたりしませんね? (2) スクリプトでは'<>'が区切り文字として使われていますが、例題はカンマで区切られています。 どちらが正しいのでしょうか? (2) サーバー上ということですが、実行はそのサーバーにログインして「perl スクリプト」のように実行ですか? それとも、WebブラウザからCGIとして実行ですか? (3) Perlのバージョンは5.?以上ですよね? まず、効率が悪い点は $namefileの1行に対して ・$classfileを最初から最後まで全部読み込むのを2回、該当行を削除した書き出しを1回 ・$namefileに途中まで更新した内容の書き出しを1回 行っていることです。ファイルの読み書きは、他の内部的な処理に比べて非常に時間のかかるものです。極力減らすのが高速化につながります。 今回のでいえば、読み込みと書き出し1回ずつ、それぞれのファイルで計4回で済みます。 後、細かい点で言えば ・flockは必要ですか? 処理中にファイルが書き変わることがあるのなら、読み書きモードでopen→flock、処理が全て終ってからclose、として、この処理の最初から最後まで他の処理が入らないようにするべきです。 そうでないなら、flockの必要はありません。 ・local(@val1) = split("<>", $line12); 一時的なローカル変数としてなら、localではなく、my を使うことをお勧めします。詳しくはネットで検索 但し、perl 4以前なら myは無いのでlocalになります。 ・@new1 = ""; リストの初期化なら、空リスト()の方がよいかと。 open(DATANAME,$namefile) ; @lines11 = <DATANAME>; #$namefileから読み込み close DATANAME ; open(DATACLASS,$classfile) ; @lines12 = <DATACLASS>; #$classfileから読み込み close DATACLASS ; %namehash=() ; # seqをキーにしたハッシュテーブルを作る # namefileからハッシュテーブルを作る foreach $lines11(@lines11){ @val = split(/<>/,$lines11) ; if ( $#val >= 1 ) { #<>の区切りがあったら、ハッシュに登録 $namehash{$val[0]} = $lines11 ; } } # classfileとハッシュテーブルとを照合する foreach $lines12(@lines12){ @val = split(/<>/,$lines12) ; if ( $#val >= 1 ) { #<>の区切りがあったら、ハッシュと照合 $seq = shift @val ; # @valの先頭を取り出す if ( exists $namehash{$seq ) { # 対応するキーがあったら $namehash{$seq} =~ s/\n//; # 行末の改行コードを削除 $namehash{$seq} .= "<>" . join("<>",@val); # $seqを除いた部分を追加する $lines12="" ; # foreachでは、ループ変数を書き換えると、元のリストの内容が書き変わる } } } #結果の書き出し open(DATANAME,">" . $namefile) ; #全てのキーについて、その内容を書き出す foreach $key (sort ( keys %namehash )) { print DATANAME $namehash{$key} ; } close DATANAME ; #残ったクラスデータの書き出し open(DATACLASS,">" . $classfile) ; print DATACLASS @lines12 ; close DATACLASS ;
その他の回答 (1)
- kumoz
- ベストアンサー率64% (120/185)
実際の件数が不明なのでうまくいくかはわかりませんが、1つの配列にクラスデータと名前データを 読み込んで処理するのが効率的だと思います。 use strict; my $list = join '', map { /(.*年)\n$/ ? $1 : $_ } sort { $a <=> $b } <DATA>; print "$2$1\n" while $list =~ /\d+(.*?年)(.*)\n/g; __DATA__ 1,1-1,1年 2,1-2,1年 3,1-3,1年 4,2-1,2年 5,2-2,2年 6,3-1,3年 7,3-2,3年 1,田中,たなか 2,伊藤,いとう 3,斎藤,さいとう 4,上野,うえの 5,大阪,おおさか 6,福島,ふくしま 7,矢部,やべ ここでは <DATA> ファイルハンドルを使っていますが、2つのファイルから読み込むには 次のようにします。なお、ファイルのオープン・クローズのコードは省略しています。 my @list = <FILE1>; # クラスデータ push @list, <FILE2>; # 名前データ my $list = join '', map { /(.*年)\n$/ ? $1 : $_ } sort { $a <=> $b } @list; print "$2$1\n" while $list =~ /\d+(.*?年)(.*)\n/g;
お礼
kumozさん 回答ありがとうございます。 なるほど1つの配列にまとめて対処するんですね。 ちょっとやってみます!!
お礼
kmeeさん 回答ありがとうございます。 >別のファイルに出力するのではないですね? はいその通りです。 >一つ目の値で統合するのですね?この値は重複してたりしませんね? はい。そうですが、重複する可能性はあるかもしれません。 説明不足で申し訳ございません >スクリプトでは'<>'が区切り文字として使われていますが、例題はカンマで区切られています。 >どちらが正しいのでしょうか? ごめんなさい。「<>」になります。 >サーバー上ということですが、実行はそのサーバーにログインして「perl スクリプト」のように実行ですか? >それとも、WebブラウザからCGIとして実行ですか? WebブラウザからCGIとして実行になります。 >Perlのバージョンは5.?以上ですよね? はい。5以上になります。 >但し、perl 4以前なら myは無いのでlocalになります。 ありがとうございます。そうなんですね。勉強になります。 >@new1 = ""; >リストの初期化なら、空リスト()の方がよいかと。 ありがとうございます。 今後はそのようにいたします。 ハッシュについても、まだ完全に理解し切れていないですが、今後今回の件で使う機会がありそうなので これを機会にちょっと使ってみようかと思います。