Perlでのデータ処理についての初歩的な質問

このQ&Aのポイント
  • Perlでデータ処理を行っている際の初歩的な質問について解説します。
  • データ処理を進めて得られたデータについて、合計値を出力する方法を解説します。
  • 複数のデータがある場合は、後ろのデータを足し合わせるルールに従って処理します。
回答を見る
  • ベストアンサー

Perlでのデータ処理について初歩的な質問

現在Perlでデータ処理をしています。処理を進めていき、下のようなデータを得ることができました。 Question1 1→2 2→4 3→3 2→6 4→4 Question2 1→2 3→4 2→3 4→2 3→3 このようなデータがa.txt,b.txt,,,e.txtというように5個あります。 これらのデータからそれぞれ、Question1の1,2,3,4とQuestion2の1,2,3,4の→のあとの数字の合計をa_out.txt,b_out.txt,,,e_out.txtとして一気に出力させたいです。 ただし、Question1に2→4と2→6のように、二つのデータがある場合は、より後ろにあるデータ(この場合だと2→6)を足し合わせることにしたいと思っています。 明快な方法がなかなか思いつかないので、力を貸していただけたらと思います。

  • Perl
  • 回答数5
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
  • g_p_
  • ベストアンサー率53% (28/52)
回答No.3

#! perl use strict; use warnings; my @names = qw(a b c d e); my $txt = q(.txt); for my $name (@names) { # 要るヤツ my $result = { Question1 => { 1 => 0, 2 => 0, 4 => 0, }, Question2 => { 2 => 0, 4 => 0, } }; open my $in, '<', qq($name$txt) or die $!; my $question; while ( my $line = <$in> ) { chomp $line; next unless $line; if ( $line =~ /^(\d+)→(\d+)$/ ) { next if exists $result->{$question}->{$1}; $result->{$question}->{$1} = $2; } else { $question = $line; } } close $in or die $!; open my $out, '>', qq(${name}_out$txt) or die $!; my $total; for my $questions ( keys %{$result} ) { $total += $_ for values %{ $result->{$questions} }; } print {$out} qq(total=$total\n); close $out or die $!; } exit; __END__ やっつけ度満点ですが、こんな感じでどうでしょ。

maguro141
質問者

お礼

ありがとうございます. #要るヤツ の部分って使わないデータを0にすればいいんですよね?このプログラムの場合ではQuestion1の1,2,4とQuestion2の2,4以外のデータが足し合わされるということでいいでしょうか?

その他の回答 (4)

  • g_p_
  • ベストアンサー率53% (28/52)
回答No.5

すみません、 間違ってました。 >next if exists $result->{$question}->{$1}; >ココで該当するハッシュのキーが存在しなかったら、読み飛ばしているつもりなんですけど。 ぜんぜん読み飛ばしてませんね。not が抜けてます。 next if not exists $result->{$question}->{$1}; でした。 二度も書き込んで見逃してました。すみません。 もうお分かりでしょうが、要らないキーを設定するも良し、 必要なキーを設定するも良し、いくらでもやり方はあるって事ですね。 とにかく間違ってましたすみません。

maguro141
質問者

お礼

うまくいきました! next if not exists $result->{$question}->{$1}; と my $result 以下の部分を書き換えることで色々なパターンに対応できますね. 丁寧にありがとうございました!

  • g_p_
  • ベストアンサー率53% (28/52)
回答No.4

>#要るヤツ >の部分って使わないデータを0にすればいいんですよね? >このプログラムの場合ではQuestion1の1,2,4とQuestion2の2,4以外のデータが足し合わされるということでいいでしょうか? いや逆です。 どこまで説明すれば良いかアレですが、 要は、ファイルを読む前に、 # 要るヤツ my $result = { Question1 => { 1 => 0, 2 => 0, 4 => 0, }, Question2 => { 2 => 0, 4 => 0, } }; で、結果を格納するハッシュを初期化していて、 next if exists $result->{$question}->{$1}; ココで該当するハッシュのキーが存在しなかったら、読み飛ばしているつもりなんですけど。 期待した結果が出なかったんですかね?

  • g_p_
  • ベストアンサー率53% (28/52)
回答No.2

>上のa.txtの場合だと"total=25"といった感じに なら、手っ取り早く、 これを for my $num ( sort keys %{$result} ) { my $total; $total += $_ for values %{ $result->{$num} }; print {$out} qq($num→$total\n); } これに my $total; for my $num ( sort keys %{$result} ) { $total += $_ for values %{ $result->{$num} }; } print {$out} qq(total=$total\n); でどうでしょ。 $total の宣言場所と出力位置を変えただけです。

maguro141
質問者

お礼

わざわざありがとうございます! 追加で質問なんですけど,この場合って $total += $_ のところで,数字を順番に足していっているんですよね? もしも,Question1の1,2,4とQuestion2の2,4だけを足し合わせたい場合だとプログラムを結構変えないといけなくなりますか?

  • g_p_
  • ベストアンサー率53% (28/52)
回答No.1

こんなんでどうですか? #! perl use strict; use warnings; my @names = qw(a b c d e); my $txt = q(.txt); for my $name (@names) { my $result; open my $in, '<', qq($name$txt) or die $!; my $question; while ( my $line = <$in> ) { chomp $line; next unless $line; if ( $line =~ /^(\d+)→(\d+)$/ ) { next unless $question; $result->{$1}->{$question} = $2; } else { $question = $line; } } open my $out, '>', qq(${name}_out$txt) or die $!; for my $num ( sort keys %{$result} ) { my $total; $total += $_ for values %{ $result->{$num} }; print {$out} qq($num→$total\n); } close $out or die $!; close $in or die $!; } exit; __DATA__ 読み込むファイルとか出力する形式とか分からない部分もありますが、 大体こんな感じでよくないですか? 他にもうまいやり方はあるでしょうけど。参考までに。

maguro141
質問者

お礼

ありがとうございます.きちんと動きました. 私の説明が下手くそで質問の意図が伝わらなかったかもしれませんが,私が出力したかったのはQuestion1の1から4までの数字とQuestion2の1から4までの数字をすべて足し合わせたものです. (上のa.txtの場合だと"total=25"といった感じに) うまく説明できずにすみません...

関連するQ&A

  • Perlでの文字列処理について

    プログラム初心者です。 Perlで下記のような文字列処理のプログラムの書き方がわからず、質問させて頂きました。 【内容】 FILE_A.txtが「!」マークで区切られていて、「!」マークの下行の文字列をIPアドレスの右横に移動したものをFILE_B.txtに出力するという処理です。 「!」マークの下行の文字列の「name」は共通です。 -------------------------------------------- 【FILE_A.txt】 ! name abcdeLV 123.123.123.123 123.123.123.124 123.123.123.125 ! name fghijLV 10.10.10.11 10.10.10.12 10.10.10.13 10.10.10.15 10.10.10.16 ! -------------------------------------------- ↓ -------------------------------------------- 【FILE_B.txt】 123.123.123.123 abcdeLV 123.123.123.124 abcdeLV 123.123.123.125 abcdeLV 10.10.10.11 fghijLV 10.10.10.12 fghijLV 10.10.10.13 10.10.10.15 fghijLV 10.10.10.16 fghijLV -------------------------------------------- 上記のようなPerlでの処理を具体的に教えて頂ければうれしいです。 本サイトのようなものを利用するのが初めてですので、不手際があるかもしれませんが なにとぞよろしくお願いいたします。

    • ベストアンサー
    • Perl
  • Perlでのファイル内データ処理方法について

    プログラミングを始めたばかりです。 Cygwin上でPerlを行っています。 下に示すように、計算プログラムの中にデータを記入し、そのデータを処理することは出来たのですが、外部のファイルを読みそのデータを処理する方法が分かりません。 # y = ax + bを求める @x=(1,2,3); @y=(1,4,9); for($i=0;$i<$n;$i++){ $A = $A + ($y[$i] * $y[$i]); $B = $B + ($x[$i] * $x[$i]);   ・   ・   ・ $a=・・・ $b=・・・ print("a=$a,b=$b"); パールファイル(.pl)内に @x=(1,2,3); @y=(1,4,9); のように記載すると、データが変わるたびにファイル内の数値を入れ替えないといけないと思うのですが、cygwinのウィンドウに、 $ ./lesson.pl 10 <data1.csv のように入力しEnterすると、ファイル内の数値を入れ替えないで指定したファイル(ここではdata1.csv)のデータが処理されると思うのですが、その場合パールファイルをどのように記述すればよいのでしょうか。また、cygwinのウィンドウにどのように入力すればよいのでしょうか。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • perlでの出力先設定

    perlの出力結果を.txtにして出力しているのですが、出力先が.plのあるところ以外に指定することはできるのでしょうか? <STDIN>でtxtデータを読み込んでいるのですが、例えば入力したtxtがCドライブのAというフォルダにある場合Aのフォルダ内に出力結果を出し、WドライブのBというフォルダのtxtを入力した場合はBのフォルダ内に出力結果を出したいです(入力したtxtと同じ場所に出力したい)。 わかる方がいたら教えてください、お願いします。m(_ _;m)

  • perl初心者です。宜しくお願い致します。

    ファイルの容量が大きく。perlを使用してデータの集計をしています。 "A"がきたらflag1をたてなさい。 "B"がきたらflag2をたてなさい。 "C"がきたらflag3をたてなさい。 これでAとBとCを抜き取ること&AからCまでの時間を取得したのですが、 Bの数のmaxの値だけを抜き取りたいのですが、Bがきたときの数をすべて 出力してしまいます。下記の文だと、Bが4回きたら、1,2,3,4と出力してしまいます。 それで4だけを出力したいのですがどのように書き換えたらようか教えて頂けますでしょうか。 '----------------------------------------------------------------------------- open (IN,"< $ARGV[0].txt") or die; open (OUT,"> $ARGV[0]_out.txt") or die; $flag =0; my $a, $b, $c; $count = 0; ####################################################### while($line =<IN>){ ($time,$data) = split(/\s+/,$line); if($data eq "A") { $flag=1; $a = $time; #print OUT $line; #print OUT "\n"; } elsif($data eq "B"){ $flag=2; $count++; $count == $data; print OUT ("$count\n") } #print OUT ("$count\n"); elsif($data eq "C"){ $flag=0; $count=0; $b = $time; $c = $b - $a; print OUT ("time $c\n") } } -------------------------------------------------------------------------------

  • perl ファイルのデータを編集したい

    初めまして、perl をやり初めたばかりです。作業は Linux 上で行ってます。 あるテキストファイル data.txt があります。 data.txt の中は、以下のようになっているとします。 100 200 300 400 500 600 これを読み込んで、例えば、 1 2 3 4 5 6 以上の様に各数字を百分の一にして出力したいと思ってます。 一応、色々と調べながらプログラムを書いてはみましたが 思う様に出力されません。以下そのプログラム。 #!/usr/bin/perl open(IN, "data.txt") or die ; @x = <IN>; close (IN); $ref_x = \@x; $n_data = @x; for ($i = 0; $i< $n_data; ++$i) { $$ref_x[$i] /= 100 ; print $x[$i], " "; } print"\n"; どなたか、perl にお詳しい方教えていただけないでしょうか? 宜しくお願い申し上げます。

  • 【初歩的質問】重複データがある時のハッシュへの代入について

    perl5.8です。すごくしようもない質問で申し訳ないのですが、次のようなファイルfile.txtの内容を、ハッシュ%hashに入れていくとします。 --- file.txtの中身 --- a,1 c,3 a,1 b,2 c,3 ----------------------- --- ソース(抜粋) ----- open(IN, "file.txt"); @data = <IN>; close(IN); %hash = (); foreach(@data){ chomp $_; @out = split(/,/, $_); $hash{$out[0]} = $out[1]; } ----------------------- 上記の結果は当然ながら、$hash{a}=1,$hash{c}=3,$hash{b}=2となるのですが、重複したデータを読み込んでハッシュに入れようとした時に、ワーニングなりエラーがなにも出なかったのがちょっと気持ち悪いです。重複したキーを読み込んだ時は、内部的には黙ってはじいてくれていると解釈してよいのでしょうか?そうだとすると、こういう書き方は、重複した行を排除するテクニックとなりえるのでしょうか?

  • 初歩的な質問です

    perlを学んで間もないのですが、 一致したデータを取ってくるスクリプトを組んでます。 数字の3変数$A,$B,$Cが1万データあったとき $Aが同じかつ$Bが同じ$Cを返したいのですが… すいません。どなたか教えてください。

  • エクセル!!初歩的質問・・・

    エクセルで A1 B1 C1 D1  E1  2  1  2  3 「????」 と数字が入っていて、その数字の意味は Aが500円 Bが600円 Cが700円 Dが800円です、 E1で数字の合計ではなく金額の合計を出したいのですが、初心者の為数字の合計しか出せません。 教えてください。

  • Perlで2つのテキストファイルの処理する方法2

    めぐみです。 tatsu99さま、先日は親切にアドバイス頂きまして本当にありがとうございました。 恐れ入りますまた追記で質問させて頂きたいことがありましてご連絡させて頂きました。 複雑そうなので無理そうでしたら読み飛ばしてくださいませ。 先日アドバイス頂いた出力結果にプラスして以下のデータを計算して出力させることは可能でしょうか?昭和と平成の処理です。 1.B.txtの1行目を参照します。 2.1926から1989の場合:   下二桁マイナス25にします。   例えば1986の場合、1986-25=61      1990から1999以降の場合:   下二桁マイナス88にします。   例えば1996の場合、1996-88=8   2000以降の場合:   下三桁000を100と考えてそれにマイナス88にします。   例えば2013の場合、136-88=25   それ以外のデータは無視します。 3.追加の出力データ   例えばB.txtのデータが下記のような場合   1986   3   6   以下のデータも追加出力したいです(A.txtがKATOの場合)。 kato6136 kato61 kato610306 6136kato 61kato 610306kato 610306 6136 61 以上、よろしくお願いいたします。 いつも誠意あるご回答をただ来まして本当にありがとうございます。 めぐみ

  • VC++でperlプログラムを動かすには

    VC++でOpenGLを動かしているんですが, その途中でperlのプログラムを動かしたい場合,どうしたらよいのでしょうか? 詳しい動きとしては, 1.perlのプログラムを動かして,txtデータを出力する 2. その出力したtxtをOpenGLの中で読み込んで,描画を表示 3.再びperlのプログラムを動かして,新しいtxtデータを出力する 4. その出力したtxtをOpenGLの中で読み込んで,描画を表示 この繰り返しです. この一連の動作をVC++でいっぺんに行いたいのですが, 可能でしょうか? 何かもっと詳細が知りたい場合は,なんでも聞いてください! よろしくお願いします.

専門家に質問してみよう