アプリ版:「スタンプのみでお礼する」機能のリリースについて

ハッシュを使った集計結果の出力について

testフォルダに以下のファイルがあるとします。
 aaa_1、aaa_2、bbb_1、bbb_2、ccc_1、・・・

各ファイルには○△×がついた行があり、
「aaa」のファイル(aaa_1とaaa_2)の○△×の数、「bbb」のファイルの○△×の数、を集計したいと思っています。

出力イメージは以下です。
 ファイル名の一部,○の数,△の数,×の数
 aaa,13,59,37

ファイル名の一部をキーとして、
○△×の回数を値にしたハッシュで集計しようとしましたが、
以下のようになってしまいました。
,0,0,0
,0,0,0,0,0,0
aaa,13,59,0
aaa,13,59,0,13,59,37
bbb,20,10,0
bbb,20,10,0,20,10,30

ハッシュが十分に分かっていないので、おかしなことをしてるのだと思うのですが。。
ご教授くださいますよう、お願いします。


opendir(DIR, $dir);
while ($file = readdir(DIR)){
 $maru =0;
 $san =0;
 $batu =0;
 $file =~/(.*)_(.*)/;
 $name = $1;

 open(IN, "$dir/$file");
  while ( $line = <FIN1> )
  {
   chomp( $line );
   if($line =~/○/){
     $maru++;
   }elsif($line =~/△/){
     $san++;
   }elsif($line =~/×/){
     $batu++;
   }
 }
push(@{$test{$name}} , $maru,$san,$batu);
@gyou = ( $name , join ("," , @{$test{$name}})) ;
print OUT join (",", @gyou). "\n";
}
close (IN);
close (OUT);

A 回答 (2件)

> aaa,13,59,0


→ aaa_1の内容 これは予定通りのはず。

> aaa,13,59,0,13,59,37
→ すでに、この前に $test{'aaa'}として aaa_1の $maru,$san,$batu のリストが存在している。
それに aaa_2の$maru,$san,$batuを push(@{$test{$name}} , $maru,$san,$batu);として「追加」しているのだから
$test{'aaa'}=[
aaa_1の$maru,
aaa_1の$san,
aaa_1の$batu,
aaa_2の$maru,
aaa_2の$san,
aaa_2の$batu
];
となります。
これをjoinで継げて表示すれば、当然、その実行結果の通りになる。

pushはリストに「新しい要素を追加する」のであって、「既存のリストの要素に加算する」ものではありません。
期待するものにするならば、
$test{$name}[0] += $maru;
$test{$name}[1] += $san;
$test{$name}[2] += $batu;
と、それまでの値に新しい値を「加算」しなければ。

>,0,0,0
→ $file =~/(.*)_(.*)/; がマッチしないファイル名のため、$nameが空文字列''になっている
readdirには . (カレントディレクトリ)や .. (一つ上のディレクトリ)も含まれる。

if ( $file !~/(.*)_(.*)/ ) { next ; }
などとして、マッチしないファイルは処理を飛す必要があります。

>,0,0,0,0,0,0
上のaaa_2のケースと同じ。おそさく ,0,0,0ではカレントディレクトリ, ここでは親ディレクトリを処理している。


あとは
・$dirはどこから出てきた?
・FIN1はどこから?
・OUTはどこから?
・close IN の位置がおかしいのでは? while ( $line = <FIN1> )のループの終了直後だと思うのですが。(FIN1がINだとして)
・aaa_1のときとaaa_2の時の2回 aaaが表示されるが、それでいいの?

おそらく、こんなのを求めているのでは?

$dir= "." ; #検索ディレクトリ
opendir(DIR, $dir) ;
while ($file = readdir(DIR)){
 if ( ! -f $file ) { next;} #ファイルで無い場合は無視
 if ( $file !~/(.*)_(.*)/ ) {next;} #非該当ファイルは無視
 $name = $1;
 if ( ! defined( $test{$name} ) {
  # 新しい名前だったら初期化する
  $test{$name}=[0,0,0] ;
}
 open(IN, "$dir/$file");
 while ( $line = <IN> ){
  # chomp( $line ); #chomp必要ですか?
  if($line =~/○/){
   # $maru++; と別変数に入れて後で足すくらいなら、
   $test{$name}[0] ++ ; #と最初から足せばよい
  }elsif($line =~/△/){
   $test{$name}[1] ++ ;
  }elsif($line =~/×/){
   $test{$name}[2] ++ ;
  }
 }
 close IN ; #whileが終れば、ファイルは入力済み
}
#全ファイル終了
closedir DIR ;

open(OUT,"output.txt"); #出力ファイル
foreach $name (keys %test) {
 print OUT join (",", $name, @{$test{$name}}) . "\n";
}
close OUT;
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます!
pushでは加算できないんですね。確かにそうですよね。。
readdirも適当に使っていたのでとても勉強になりました。
基本的なところから勉強し直さなくては。

あ、ディレクトリは引数で指定するつもりでしたので、それが$dirになります。
(perlの内容全てを書いていませんでした)

説明も丁寧で大変役に立ちました。本当にありがとうございました。
できるようになりました!

お礼日時:2010/06/26 23:35

ハッシュと言うのは、%で宣言する変数です。


ハッシュを使うコーディングじゃ無いみたいですけど。
何をハッシュのキーにしたいのでしょうか?
意図を説明して下さい。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
キーは$name、値は$maru,$san,$batuの回数です。

お礼日時:2010/06/26 22:26

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!