• 締切済み

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

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となるのですが、重複したデータを読み込んでハッシュに入れようとした時に、ワーニングなりエラーがなにも出なかったのがちょっと気持ち悪いです。重複したキーを読み込んだ時は、内部的には黙ってはじいてくれていると解釈してよいのでしょうか?そうだとすると、こういう書き方は、重複した行を排除するテクニックとなりえるのでしょうか?

  • aneja
  • お礼率93% (379/405)
  • Perl
  • 回答数2
  • ありがとう数3

みんなの回答

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.2

もし、最初の一回だけの代入を有効にしておいて 上書き使用したときに警告なりエラーなりにしたいというのなら、 この辺のモジュールを使って対処することになるでしょう。 Tie::Hash, Tie::StdHash, Tie::ExtraHash - base class definitions for tied hashes - search.cpan.org http://search.cpan.org/~nwclark/perl-5.8.8/lib/Tie/Hash.pm すでに誰かが作っているような気もしたのですが、 それらしい名前のものは見つかりませんでした。

aneja
質問者

お礼

ご回答どうもありがとうございました。 CPANであったのですね。探してくださってありがとうございます。 もっと勉強したいと思います。

  • Werner
  • ベストアンサー率53% (395/735)
回答No.1

 $a = 1;  $a = 1;  $a = 2; がワーニングやエラーにならないのと同じこと。 変数を更新しただけでエラーなんて出ない。 > こういう書き方は、重複した行を排除するテクニックとなりえるのでしょうか? なり得るけど、キーが重複していると上書きされるので、その例の場合、  a,1  a,2 の2つがあった場合に最後の $hash{"a"}=2 しか残らない。 それでよければそのまま使えば良いし、 そうでなければ適当に修正して使えばよい。

aneja
質問者

お礼

ご回答どうもありがとうございました。 ご回答くださったように、確かに普通のスカラー変数で考えるととってもあたりまえのことですね。 ハッシュを勉強したてで、「キーはユニークだし」という強迫観念(?)がこのようなアホな疑問を生んだのかもしれません。

関連するQ&A

  • 先頭の単語が一致した時のデータ追加

    【データ】 (A) A A2 "one" 7 A 3C three 9 B DD "two" 11 C CDE four 25 C 4D five 33 D YY six 27 ・ ・ (B) A okinawa kagoshima miyazaki B kumamoto oita D fukuoka E saga nagasaki ・ (A)と(B)のデータを比較し、先頭の単語が一致した時のみ、先頭の単語を除いた(B)の行を (A)の末尾に加えるという処理をしたいです。 【目標】 A A2 "one" 7 okinawa kagoshima miyazaki A 3C three 9 okinawa kagoshima miyazaki B DD "two" 11 kumamoto oita C CDE four 25 C 4D five 33 D YY six 27 fukuoka ・ ・ 以前、回答して頂いた方法を踏まえ、以下の処理を行いましたが上記のような結果がでません。 宜しくお願いします。 #!/usr/bin/perl open(FILE1, "<aaa.txt") || die "File1 Open Error! \n"; open(FILE2, "<bbb.txt") || die "File2 Open Error! \n"; open(OUT, ">zzz.txt") || die "OUT Open Error! \n"; my @data1 = <FILE1>; my @data2 = <FILE2>; chomp @data1; chomp @data2; foreach my $line1 (@data1) { my @array1 = split(/\t/, $line1); push @{$hash1{$array1[0]}}, @array1[1, -1]; for my $key1 (sort keys %hash1){ foreach my $line2 (@data2) { my @array2 = split(/\t/, $line2); push @{$hash2{$array2[0]}}, @array2[1, -1]; for my $key2 (sort keys %hash2){ if($key1 eq $key2){ print OUT join("\t", ($key2, @{$hash2{$key2}}, @{$hash1{$key1}})), "\n"; } } } } }

    • ベストアンサー
    • Perl
  • CSVデータの編集の際の重複チェックの方法

    今、data.csv(カンマ区切り)として、左から順位、名前、性別という3項目で、10人程度のリストデータがあります。 data.csv(カンマ区切り)を編集するようにしていますが、順位は重複してはならないので、重複していたらエラーを出したいのですが。。。 ($rank,$name,$sex) = split(/\,/,$line); です。 open(IN,"$logfile") || &error("ファイルが開けません"); @lines = <IN>; close(IN); # 情報の書換え foreach $line (@lines) { ($rank,$name,$sex) = split(/\,/,$line); $line = "$in{'rank'},$name,$sex\n";} push(@new,$line); } # ファイルを更新 open(OUT,">$logfile") || &error("ファイルが開けません"); print OUT @new; close(OUT);

  • テキストファイルになにも入っていないのを確認して・・・

    書き込みファイル(.txt、.datなど)は最初データは入っていませんよね。空っぽです。 そのときにある変数に0や1を入れたいのですが、ちゃんと認識してくれません。 書き込みファイルの内容は@txtに入っているとします。ただし、まだデータは1件も書き込まれていません。 foreach (@txt) { chomp; ($id, $tonum, $c_date, $c_status, $chkbox) = split(/,/, $_); if( !$_ ){ $id = 0;} として、$idに0を入れたいと思ったのですが、 記録された内容は、 1,1020,2006/9/14,E,0 ,1020,2006/9/14,B,0 →ココ でした。つまりなにも入っていないのです。 ここに値を入れる方法を教えてください。

    • ベストアンサー
    • Perl
  • foreach構文をwhile構文で実現したい。

    下記にありますforeach構文をwhile構文で実現しようと試みているのですが 何故か同じように実現できず、無限ループになっているような気がします。 どこに問題があるのか当方ではわからない為、どなたかご教授いただけませんでしょうか。 ------------------------------ $ cat list1.txt 01<>ああああ 01_01<>あAAA 01_02<>あBBB 01_03<>あCCC 01_04<>あDDD 02<>いいいい 02_01<>いAAA 02_02<>いBBB 02_03<>いCCC 02_04<>いDDD ------------------------------ ■成功版 open(IN, "<list1.txt"); @datas = <IN>; close(IN); open(OUT, ">date.txt"); foreach (@datas) { chomp; ($a, $b) = split(/<>/, $_);#$_は省略できます。 print OUT "'$a'=>'$b',\n"; } close(OUT); ■取組版 open(IN, "<list1.txt"); @datas2 = <IN>; close(IN); open(OUT, ">date2.txt"); while (@datas2) { s/^/'/; s/<>/'=>'/; s/$/',/; print OUT; } close(OUT);

    • ベストアンサー
    • Perl
  • 重複データ削除

    DOSプロンプトでテキストファイルの重複データを削除するコマンドはあるのでしょうか? また、新、旧のデータを持つファイルがあり新データを旧データに上書きする時に重複データは上書きしないコマンドはあるのでしょうか? 今はtype a.txt>>b.txtで実行して重複データを手作業よって削除してます。 どなたかご教授願います。

  • perl 計算結果をファイルへ出力したい

    perl やり始めたばかりです。宜しくお願いします。 入力ファイル data.txt があるとします。 data.txt は、 123 456 789 333 555 777 以上のようなテキストファイルといたします。このファイルを 以下の様に100分の1にして出力したい。 1.23 4.56 7.89 3.33 5.55 7.77 と言うことで、この場で教えていただきました。それが、以下です。 #!/usr/bin/perl open(IN, "data.txt") or die ; @x = <IN>; close (IN); foreach $line (@x){ chomp($line); @elms = split(' ',$line); foreach $data (@elms){ print $data/100," "; } print "\n"; } おかげ様でこれはこれで上手く動きました。そこで、出力値をファイルに 書き込みたいのです。 もちろん、以下の様な方法でファイルに 書き込めるのは判っております。 計算プログラム.pl > outfile.txt しかし、上のプログラムをベースにファイルに書き込めないかと色々と 試してはみましたが、どうも上手く行きません。 どなたか教えて頂けないでしょうか? 宜しくお願い申し上げます。

    • ベストアンサー
    • Perl
  • excel→txtファイル作成時、セル間にできることがある「”」を指すメタ文字

    Perlで書いたプログラムでデータファイルを用いるため、Excel→txt形式(タブ区切り)でファイルを保存し、perlでそのテキストファイルのデータをprintしてみると、セルとセルの間に「”」というような記号が入ってしまうことがあります。 これをsplitで省くことはできますでしょうか?その際に用いるメタ記号も教えていただけないでしょうか?各要素を取り出すためにいい方法があれば教えてください。 (1)元のExcelファイル id 2000 2001 2003 001 A_IN A_IN B_IN 002 B_IN B_IN OUT (2)テキストファイル(タブ区切りで保存) id 2000 2001 2003 001 A_IN A_IN B_IN 002 B_IN B_IN OUT (3)以下のようなperlプログラムでprint表示させると「"」という記号が入ってしまい、要素ごと(例えばA_IN、OUT)にデータ処理を行うことができません。 「プログラム」 #import txt file my $errmsg = "can not open $data\n"; my @data0; open(FID, $data) or die $errmsg; chomp(@data0 = <FID>); close FID; my $number = @data0; for (my $i=1; $i<$number; $i++) { my @a = split(/\r/, $data0$i]); my @b = split(/\t/, $a[0]); print @b, "\n"; ←このprintの結果が以下のようになります。 print $b[0], "\n"; ←そのため、タブによるsplitがうまく print $b[1], "\n";  出来ておらず、これらの値も変 print $b[2], "\n";  なものが出力されてしまいます・・・。 print $b[3], "\n"; } 「結果」 001A_IN"A_IN"B_IN 002B_IN"B_IN"OUT (「”」が入る位置は何回か試したところ、変わることがありました。)

  • Perlでハッシュや配列で重複するキーについて

    ハッシュで重複するキーが値となるので、このハッシュはabdの3つのキーしか存在しないということでしょうか? %a = ('a'=>1, 'b'=>2, 'a'=>3, 'd'=>4); また、配列の場合はabadと4つ数になるということでしょうか? @a = ('a','b','a','d'); この場合配列で、重複する値を抽出するアルゴリズムが知りたいです。

    • ベストアンサー
    • 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
  • このプログラムなんですが

    #! /usr/bin/perl @data=<>; open (IN,"newtype.txt"); @file = <IN>; close (IN); foreach $address (@file) { ($pn,$ad) = split(/\t/,$address); $pnad{$pn}=$ad; } foreach $jusyo (@data) { chomp $jusyo; print $jusyo; print "\n"; print "$pnad{$jusyo}"; } foreach $line (@file) { @data = split(/t\/, $line); if($data[0] =~ "51105") { print "$data[0]"; print "$data[1]"; } elsif($data[0] =~ "651130") { print "$data[0]"; print "$data[1]"; } } exit; コンパイルするときには ./sample.pl data.txt をシェルにうって実行します。 このプログラムでは、はじめに自分で指定したファイル内に存在する郵便番号(通常は7桁だけなんですが、プログラムを見ていただければわかると思われますが、それ以外に5桁(たとえば12354XX,x12354x,xx12354など))と6桁(134567x,x134567など)がありまして、それを表示させたいんですが、上のプログラムでは、if文以下の5桁と6桁があった場合にそれを同時に表示させるプログラムができていないんです。 ハッシュをもちいてプログラムを作り直したいんですが、教えてください。 今日の夜8時までに出さなくてはいけないので、すぐに回答をいただけたらありがたいです。

専門家に質問してみよう