perlのeach関数の動きについて

このQ&Aのポイント
  • perlのeach関数の動作について調査してみました。perl5.8では、each関数を使用するとハッシュ内にあるデータが取得できない場合があります。
  • 対策としては、keys関数を使用することで代用することができます。eachでループすることは無理ですが、keysを使用すれば問題なくハッシュ内のデータを取得することができます。
  • PHPではreset関数が配列に対して使用されますが、perlではreset関数の代替となる明確な関数は存在しません。そのため、keys関数を使用してデータを取得することを推奨します。
回答を見る
  • ベストアンサー

perlのeach関数の動き?

perl5.8ですがeach関数を使って何回か動かすと、ハッシュ内にあるはずのデータが取得できなくなります。 my %hash = ('a'=>100, 'b'=>50); for(1..100){ while( my ($k, $v) = each %hash ){ if($k eq 'a'){ ... 通過しなくなる。 } } } PHPでは、配列に対してですが、reset関数というものがありますが perlでは、何か対策でもあるのでしょうか? 現在は、keys関数で代用しています。 eachでループは無理なのでしょうか?

  • Perl
  • 回答数1
  • ありがとう数0

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

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

Perl ではハッシュごとにこっそりと反復子があって, each や keys, values ではこの隠れた反復子を走査します. この反復子は ・each で全部調べ列挙し終えた ・keys を使った ・values を使った のいずれかの時点でリセットされます. 逆に言えば, これらのいずれかできちんとリセットしないと正しく動作しないはずです. このようなループは, each だとつくりにくいです.

関連するQ&A

  • eachとイテレーター

    each関数について質問させていただきます。perl5.8.0です。 eachに渡す引数を、ハッシュ“変数”ではなくハッシュ記法を直接指定する方法はないでしょうか。 具体的には、 %hash = (a=>1,b=>2); while (($k,$v)=each %hash) { ~ ではなく、 while (($k,$v)=each (a=>1,b=>2)){ ~ というように、eachに直接キーと要素を渡したいのです。 以下のようにいろいろ試したのですが、うまくいきません。 【1】 perl -e 'while (($k,$v)=each (a=>1,b=>2)){print "$k:$v\n";}' Type of arg 1 to each must be hash (not list) at -e line 1, near "2)" Execution of -e aborted due to compilation errors. 【2】 perl -e 'while (($k,$v)=each %{a=>1,b=>2}){print "$k:$v\n";}' syntax error at -e line 1, near "%{" Execution of -e aborted due to compilation errors. 【3】 perl -e 'while (($k,$v)=each %{(a=>1,b=>2)}){print "$k:$v\n";}' (何も出力されない) 【4】 perl -e 'while (($k,$v)=each %{{a=>1,b=>2}}){print "$k:$v\n";}' a:1 a:1 a:1 a:1 : (無限ループ) 予想では【3】の書き方が正しいような気がしましたが出力されず、そして【4】は少なくとも参照はできているようなのに、イテレーターが正しく動作していないような感じです。 (そもそもイテレーターというのは変数じゃなく無名ハッシュのようなものでも有効なのでしょうか?) また、試しにkeysで同じことをしてみると、 【5】 perl -e 'foreach (keys (a=>1,b=>2)){print "$_\n";}' Type of arg 1 to keys must be hash (not list) at -e line 1, near "2)" Execution of -e aborted due to compilation errors. 【6】 perl -e 'foreach (keys %{a=>1,b=>2}){print "$_\n";}' syntax error at -e line 1, near "%{" Execution of -e aborted due to compilation errors. 【7】 perl -e 'foreach (keys %{(a=>1,b=>2)}){print "$_\n";}' (何も出力されない) 【8】 perl -e 'foreach (keys %{{a=>1,b=>2}}){print "$_\n";}' a b keysでは【8】が期待どおりの動作をします。 どうぞよろしくお願いいたします。

    • ベストアンサー
    • Perl
  • perl 配列名変数指定するには

    perlプログラムで for文で ループ分の配列定義するには どうしたらよいですか? 下記のようなことができないかと 考えております。 for(my $i = 0; $i < $file_no; $i++){ my @{"segments$i"} =(); #配列定義 my ${"line$i"}="";     #変数定義 my %{"hash$i"}= ();    #ハッシュ定義 open(ARG1,$ARGV[$i]); while(<ARG1>){ ${'line'.$i} = $_; chomp ${'line'.$i}; @{'segments'.$i} = split(/\t/,${'line'.$i});        ${'hash'.$i}{${'segments'.$i}[0]}=${'segments'.$i}[1];     } close(ARG1); } #下記で、その後 各ハッシュに設定したデータをもとに いろいろ計算したい foreach my $a (keys %{'hash'.$i}){ ・・・ } 今は、Can't declare array dereference in "my" at test.pl line XX, near "} =" と 配列定義でエラーとなり処理できません。

    • ベストアンサー
    • Perl
  • 静的ハッシュの配列のキーに対応する値の数の多さ順で表示させたい

    ハッシュのキーに対応する値の数の多さ順で表示させたいと考え、下記の所まで試行錯誤しておりますが、どうにも思ったようにソートできずにおります。 #!/usr/bin/perl use strict; my(%a, $i, $j ,$allarray ,@keys ,@keys2 ,%hash ,%files ,$a_mumei_ref ,$key ,$value ,@value ,$x ,$files); # ハッシュの配列を静的に作る %a = ( '0' => [ qw(0) ], '1' => [ qw(1 1) ], '3' => [ qw(3 3 3) ], '7' => [ qw(7 7 7) ], '2' => [ qw(2) ], '4' => [ qw() ], '5' => [ qw() ], '6' => [ qw() ], '8' => [ qw(8 8) ], '9' => [ qw(9) ], ); @keys = sort { $hash{$b} <=> $hash{$a} || length($b) <=> length($a) || $a cmp $b } keys %a; #ハッシュのキーを数字順で表示 foreach (@keys){ print $_ ."\n"; } # 静的に作ったハッシュの配列を取り出してみる foreach $i (sort keys %a) { for ($j = 0; $j <= scalar(@{$a{$i}})-1; $j++) { print '$a{'. $i. '}['. $j. ']='. $a{$i}[$j]. ' '; } $allarray=scalar(@{$a{$i}})-1; print "No$i:kosuu:$allarray"; print "\n"; #配列の値の個数を調べその配列を作成 my($a_mumei) = $allarray; $a_mumei_ref = \$a_mumei; $files{"$i"}=($i,$a_mumei_ref); } #each関数で%filesの中身を表示 while ( ( $key , $value ) = each %files ){ print "key:$key value:$$value\n" ; } #試行錯誤 foreach $x (sort { $files{$b} <=> $files{$a} } keys %files){ print "$x => $files->{$x}\n"; } @keys2 = sort {$hash{$a} <=> $hash{$b}} keys %files; #@keys2 = sort { $hash{$b} <=> $hash{$a} || length($b) <=> length($a) || $a cmp $b } keys %files; #@keys2 = sort { $hash{$a} cmp $hash{$b} } keys %files; print "@keys2\n"; print "\n"; __END__; 私のイメージしておりますのは、ソートした結果がハッシュのキーに対応する値の数の多さ順で下記のように表示させたいのですが、 どのようにすれば可能でございますか、ご教授願えませんでしょうか key:3 value:2・・・この場合valueは配列の個数 key:7 value:2 key:8 value:1 key:1 value:1 key:9 value:0 key:2 value:0 key:0 value:0 key:6 value:-1 key:4 value:-1 key:5 value:-1

    • ベストアンサー
    • Perl
  • Perlのデータ構造について

    Perlのデータ構造でわからないところがあります。 ハッシュの配列で、以下の構造がある場合 my %hash_array = ( 1=>["aaa", "bbb"], 2=>["ccc", "ddd", "eee"], 3=>[], 4=>["fff"] ); print $hash_array{1}[0]; # aaaが表示される。 print $hash_array{2}[2]; # eeeが表示される。 ですが、 $hash_array{1}は 2 $hash_array{2}は 3 $hash_array{3}は 0 $hash_array{4}は 1 のように個数を表示させるのは、どうすればよいでしょうか? Perlのデータ構造に詳しいサイトや書籍はありますか? また、Perl 5.6.1から Perl 5.8.7に乗りかえようとしていますが、 データ構造など大幅に変わった点はあるのでしょうか?

    • ベストアンサー
    • Perl
  • Ruby 2次元のハッシュ

    Rubyで2次元のハッシュを扱いたいです。 perlで書くと以下のような感じです。(最近perlに疎遠なので自信無いですが^^;) hash{$key1}{$key2}=$value; foreach $key1 (keys %hash){ foreach $key2 (keys %{$hash{$key1}}){ print "$hash{$key1}{$key2}\n"; } } Rubyだとどんな感じになりますか?

  • PerlでHashのキーを制限したい

    【環境】 WinXP / Perl 5.14.2 関数に値を受け渡す際にハッシュを利用しようと思っているのですが キーの typo が気になります。 検索すると Hash::Util::lock_keys() などがヒットしたのですが、 結局これはそのロジックが実行された際にエラーになる仕組みです。(よね?) できれば "プロトタイプを指定した関数に対して正しくない引数を指定した時" のように そのロジックが実行されていなくても Internal Server Error になるような方法があれば欲しいのですが… そういった方法はありますでしょうか。 ---------- 最終的にしたいことは、関数に対して 36 個の引数を渡す際に できるだけミスがないように、もしあった場合すぐわかるようにしたいです。 (しっかりテストすれば良いというのはなしで… 勿論テストはしっかりしますが) なのでハッシュでなくても何か良い方法があればそちらでも良いのですが、 引数を順番に指定する方法よりはハッシュで渡したほうが良いですよね? 他になにか渡し方あるでしょうか。 ---------- ご存知の方がいらっしゃいましたら教えてください。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • ハッシュのリファレンスを用いた処理

    ActivePerl 5.8 , WinXP SP2の環境です。 Perl スクリプトを用い、ファイルから複数のブロックからなる情報をよみとり、個別のハッシュを作り、それをリファレンスの配列としてまとめて後から参照するという操作をしたいのですが、詰まってしまいました。。 例として読み取るファイルは ---input.txt--------- >1 Jan 1 Feb 4 >2 Mar 9 Apr 3 >3 Oct 8 Nov 4 ------------------ ここから1,2,3の個別のハッシュ {Jan => 1 Feb => 4} {Mar=> 9 Apr =>3} {Oct =>8 Nov =>4} を作成し、それぞれのハッシュのリファレンスの配列をつくり、その後からすべてのハッシュの中身を個別に出力させたいと思いました。 次のようなスクリプトを作成したのですが思ったように作動しません。 use strict; open (IN, "input.txt") or die ("cant open file \n"); my $reff; my @array_of_reff; my %hash; my $count = 0; while(<IN>){ my $line = $_; ######ここでは各ブロックの頭の ">"を認識し、2個目以降であれば直前までで作ったハッシュのリファレンス($reff)を配列@array_of_reffに入れる。 if($line =~ /^>/){ if($count >0){ $reff = \%hash ; push (@array_of_reff, $reff); %hash = (); } $count++; } ########ここではアルファベットが入った行を認識して、ハッシュに追加しています if($line =~ /^[A-Za-z]/){           $line =~ /([A-Za-z]+)\s+/; my $month = $1; $line =~ /\s+(\d+)/; my $day= $1; $hash{$month} = $day;     } ###ここはファイルの最後になったら直前まで作っていたハッシュののリファレンス($reff)を配列@array_of_reffに入れる。 if( eof ){ $reff = \%hash ; push (@array_of_reff, $reff); } } #####ハッシュのリファレンスの配列(@array_of_reff)からもとのハッシュを参照し、ハッシュごとに出力 foreach my $reff_of_hash (@array_of_reff){    print "output";    while( (my $key,my $value) = each %$reff_of_hash ){     print "\n" , $key, " : ", $value, ;    } } このスクリプトを実行すると Nov 4 Oct 8 という3つめのハッシュのなかみが3回出力されてしまいます。自分では3つの別のハッシュをつくっているつもりでも、どうやら1種類しか作れていない、もしくはハッシュが上書きされているようなのですが、原因がわかりません。 この例だけ見るとハッシュのリファレンスを使う必要はないのですが、実際にはもうすこし大きいスクリプトで"ハッシュのリファレンスの配列を他のサブルーチンに渡す"ということを想定しており、これが解決できず先に進めない状態です。 アドバイス、解決法がわかったら教えていただけないでしょうか。

    • ベストアンサー
    • Perl
  • Perlの書き方について

    perlを勉強していて、似たような配列やハッシュの場合でしたらなんとか解決出来たのですが、以下の場合が思うような結果が得られず困っているので、どなたか教えていただきたく質問しました。 例) my $hoge1=10; my $hoge2=9; my $hoge3=8; my $hoge4=7; my $hoge5=6; my $hogehoge; for(1..5){ $hogehoge+=$hoge$_; } 上記の書き方の場合、「$hoge$_」でエラーが出ます。 このような場合は、どのように書けばいいのでしょうか。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • mapのポインタ

    C++標準ライブラリ map の使用法に関して質問させてください。 winXP, minGW環境最近でC++のプログラミングを始めました。 これまでperlを使っており、とくにハッシュを多用していました。 たとえば入力ファイルに区切りのついたデータがあり、区切りごとに個別のハッシュをつくり、ハッシュのリファレンスの配列を作成します。その後に配列にはいったすべてのリファレンスからハッシュを呼び出して、ハッシュのデータをつかって処理を行う などです。 *入力ファイルから区切りごとにハッシュ%hashを作成 $ref_of_hash = \%hash; push (@array_hash, $ref_of_hash); *ここまでは入力ファイルにしてループ処理 foreach $ref ( @array_hash){      %hash_again = %$ref; *ここでハッシュをつかって処理を行う。 } c++の標準ライブラリにmapがあり、ハッシュとは多少異なるとはいえ、私の使用用途には問題なかったので使い始めました。ですが、マップのポインタをつかった上記のような処理の方法がわからず困っています。 1)mapのポインタから mapの各要素を呼び出すにはどのようにしたらよいでしょうか? 2)mapのポインタをつかった場合 map<double,double>::iterator it; for( it = my_map.begin(); it != my_map.end(); it ++){ //do something } のようなイテレータを使う場合、.begin .engはポインタを使ってどのように記述すればよいでしょうか。 3)このようなmapのポインタを利用したソースが書かれているサイトなどがあれば教えていただけないでしょうか。 C++をはじめて間もないので用語の間違いや勘違いがあるかもしれませんが、よろしくお願いします。

  • ハッシュキーの内容について

    こんばんは。perlをはじめて一ヶ月あまりの初心者です。 また疑問に思うことが見つかり、質問させていただきました。 以下のようなコードがあります。 ----------------------------------------- my @array = ( 'a','b','c'); my %hash; for (@array) {   $hash{$_}{OK} = 1;   $hash{$_}{WAVE} = 2;   $hash{$_}{Perl} = 3; } print $hash{a}->{OK}; print $hash{"b"}->{WAVE}; print $hash{c}->{"Perl"}; ----------------------------------------- 1、2、3を格納するときなのですが、 ハッシュのキーになる値(OK、WAVE、Perl)は、 ダブルクォートや、シングルクォートで囲っていません。 でも、エラーも発生せず、普通に実行できてしまいます("123"を表示します)。 ハッシュのキーは、 "OK","WAVE"や、'Perl'のように ダブルクォートや、シングルクォートで 囲む必要はないのでしょうか?? C言語みたいに厳密に型が決まっているわけではないので、 OKでも"OK"でもよいのかなー、という思いはあるのですが、、、 よろしくお願いします。

    • ベストアンサー
    • Perl