• ベストアンサー

eachとイテレーター

pipipi523の回答

  • ベストアンサー
  • pipipi523
  • ベストアンサー率40% (148/365)
回答No.1

eachに無名変数を使った場合リファレンスが毎回変わるのでダメです 具体的にはこんな感じです ($k,$v)=each %{$a={a=>1,b=>2}}; print "$k $v\n"; ($k,$v)=each %{$a}; print "$k $v\n"; 結果(OK) a:1 b:2 ($k,$v)=each %{$a={a=>1,b=>2}}; print "$k $v\n"; ($k,$v)=each %{$a={a=>1,b=>2}};#$aの内容が変わる print "$k $v\n"; 結果(NG:whileにすると永久ループ) a:1 a:1 これではダメなのでしょうか? perl -e "%hash=(a=>1,b=>2);while(($k,$v)=each %hash){print \"$k:$v\n\";}"

SV576
質問者

お礼

そもそも何故こんなことをしたいのかというと、単にコードの視認性だけなんです(^^; ある設定内容を保持している %conf というハッシュがあって、値はハッシュリファレンスで2階層のレベルがあります。 %conf = ( setA => {conf1 => 'valueA1', conf2 => 'valueA2', conf3 => 'valueA3'}, setB => {conf1 => 'valueB1', conf2 => 'valueB2', conf3 => 'valueB3'}, setC => {conf1 => 'valueC1', conf2 => 'valueC2', conf3 => 'valueC3'}, ); というように初期化されているとします。 で、処理の過程で設定を追加する(つまり再初期化ではなく元の内容を保持させたまま追加する)、しかもある程度まとまった数、というコードを書きたいのですが、普通に書けば、conf4とconf5を追加するなら ${$conf{'setA'}}{'conf4'} = 'valueA4'; ${$conf{'setA'}}{'conf5'} = 'valueA5'; ${$conf{'setB'}}{'conf4'} = 'valueB4'; ${$conf{'setB'}}{'conf5'} = 'valueB5'; ${$conf{'setC'}}{'conf4'} = 'valueC4'; ${$conf{'setC'}}{'conf5'} = 'valueC5'; という感じでしょうか。 簡潔化するなら (...) = (...) という書き方もできるかもしれません。 これを、 while (my ($name, $value) = each { setA => {conf4 => 'valueA4', conf5 => 'valueA5'}, setB => {conf4 => 'valueB4', conf5 => 'valueB5'}, setC => {conf4 => 'valueC4', conf5 => 'valueC5'}, }) { $conf{$name} = {%{$conf{$name}}, %$value}; } と書けたら視認性も上がってメンテやいろいろな面で良いだろうと考えたのです。 一時的なハッシュを用意して %tmp = ( setA => {conf4 => 'valueA4', conf5 => 'valueA5'}, setB => {conf4 => 'valueB4', conf5 => 'valueB5'}, setC => {conf4 => 'valueC4', conf5 => 'valueC5'}, ); while (my ($name, $value) = each %tmp) { $conf{$name} = {%{$conf{$name}}, %$value}; } と書けばいいんですが、可能なら極力シンプルにしたかったもので。

SV576
質問者

補足

(長すぎると怒られたため補足欄に分けさせていただきます) ご回答ありがとうございます。 すみません、なんとなく解ったような解らないような…苦笑 リファレンスが変わるというのは、参照される側つまり被リファレンスのデータが、eachの実行のたびに作り直されてしまう=イテレーターも初期状態なので無限ループ、という理解でよろしいでしょうか。 で、keysは期待どおり動いたのは、参照するのは初めの1回だけで、取得した内容をメモリ上のどこかに保持している、ということなんですかね? 言い換えれば、eachを使うなら変数を用意しなきゃいけない、と理解すればいいでしょうか?

関連するQ&A

  • 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
  • 静的ハッシュの配列のキーに対応する値の数の多さ順で表示させたい

    ハッシュのキーに対応する値の数の多さ順で表示させたいと考え、下記の所まで試行錯誤しておりますが、どうにも思ったようにソートできずにおります。 #!/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
  • hashをスカラー変数に渡す

    最近、perlを勉強し始めたのですが下記のようなサンプルコードを 見たことがあります。 hashをスカラー変数「$test」に渡している。そして「%$test」でhashに変換してeachで回している。最初から「%test」のようにしてeachで回せばよいと思うのですが実際の業務とかでhashをスカラー変数で受け取るようなことってありえるのでしょうか? my $test = { a=>'test_a', b=>'test_b', c=>'test_c' }; while( my ($key, $value) = each %$test ) { print $key ." : " . $value . "\n"; }

    • ベストアンサー
    • 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だとどんな感じになりますか?

  • ハッシュの中身の表示

    ハッシュの中身の確認ができなくて困っています。 下記のような実行文においてです。 当然、test の戻り値は、スカラーとハッシュです。ハッシュを戻すときには参照渡し記号の\もつけています。 my ($return_code, %hash_data) = test(); 表示しようとすると、 Hash(0x5b04) のような表示にしかなりません、、 (試した表示方法は、下記4つです。) (環境は、WindowsXP上での、ActivePerl-5.10.0.1004 です。) foreach $key ( keys( %Hash ) ) { print "キー値 : $key\n"; print "値 : $Hash{$key} \n " } while ( ( $key , $value ) = each %Hash ){ print "キー値 : $key\n"; print "値 : $value \n " ; } use Data::Dump qw(dump); print dump(\%hash); #print %display_test; 宜しくお願いします。

    • ベストアンサー
    • Perl
  • DBIを使ってのデータの取り出しについて

    自分で作ったmysqlからデータを参照し様として #!/usr/bin/perl print "Content-type: text/html \n\n"; use DBI; #######DBIパス編集########## $DB='****' $DBusr='****' $DBpass='****' $DBtable='****' #########DBI操作############ $FIND = "SELECT a,b,c,d,e,f,g,h,i FROM $DBtable WHERE a=\'****\' limit 1"; $dbh = DBI->connect($DB,$DBusr,$DBpass); $serch = $dbh->prepare($FIND); $serch->execute; $serch = $serch->fetch; #######取り出したデータを配列に代入######## $r = 0; while( @rows = $serch->fetchrow_array ) { for( $f = 0; $f < $serch->{NUM_OF_FIELDS}; $f++ ) { $data{$serch->{NAME_lc}->[$f]}{$r} = $rows[$f]; } $r++; } while( ($key, $val) = each %data ) { while( ($key2, $val2) = each %{$val} ) { $hash{$key} = $val2; } } $a = $hash{'a'}; $b = $hash{'b'}; $c = $hash{'c'}; $d = $hash{'d'}; $e = $hash{'e'}; $f = $hash{'f'}; $g = $hash{'g'}; $h = $hash{'h'}; ##########テスト用に表示############# print "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;CHARSET=Shift_JIS\">"; print "<HTML><HEAD>"; print "<TITLE></TITLE>"; print "</HEAD>"; print "<BODY BGCOLOR=$bgc TEXT=\"$txtc\" LINK=\"$lic\">"; print "テスト:$bgc,$txtc,$lic,$button,$sight_name,$sight_tit,$bun1,$sex"; print "</BODY></HTML>"; と書いてるのですが、実行するとデータが取り出せません。 調べてみると while( @rows = $serch->fetchrow_array ) の部分でエラーが出ます。 Can't call method "fetchrow_array" on unblessed reference atと言われてしまうのですが、何か記述の仕方等何か間違ってる部分などあれば指摘お願い致します。 ちなみにデータベースへの接続等は出来ています。

    • ベストアンサー
    • Perl
  • ActivePerl-5.10.0.1004の日本語対応にする方法

    超初心者の質問ですみません。 今、Perlの絵本でActivePerlの勉強中ですが use encording"shiftjis"; $a=1; print "はじめは$aでした。\n"; $a=++; print "1増えて$aになりました。\n"; $a=--; print "1減って$aに戻りました。\n"; を実行しても、 Can't locate encording.pm in @INC (@INC contains: C:/Perl/site/lib C:/Perl/lib . ) at hello8.pl line 1. BEGIN failed--compilation aborted at hello8.pl line 1. と表示されます。 解消法を教えてください。

  • 動的ハッシュを作って取り出したいのですが・・・

    お世話になります。 フォームから送られてくるデータを動的に作ったハッシュで参照出来るように取り組んでるんですが、思ったように出来ず思い悩んでおります。 どうすれば、意図した形でデータを取り出すことが出来ますでしょうか my %FORM = ( 'd01' => 'あ', 'd02' => 'い', 'd03' => 'う', 'd04' => 'え', 'd05' => 'お', 'd06' => 'か', 'd07' => 'き', 'd08' => 'く', 'd09' => 'け', 'd10' => 'こ', ); for(sort { $FORM{$a} cmp $FORM{$b} } keys %FORM){ print "$_ = $FORM{$_} \n"; } $list="d01,d02,d03,d04,d05,d06,d07,d08,d09,d10,"; $i=-1; foreach (split/,/,$list){ $i++; $hash{$_}=$i; } for(sort { $hash{$a} <=> $hash{$b} } keys %hash){ print "$_ = $hash{$_} \n"; $view = ${"FORM$_"}; print "$view\n"; }; 最後のprint "$view\n";箇所で、 $list="d01,d02..." を split/,/,$list したので、 $FORM{d01} $FORM{d02} となるようにして、 「あ い う え お」と取り出したいのです。 ご教授のほど、よろしくお願い致します。

    • ベストアンサー
    • Perl
  • Perlで1~10まで全部足す。簡単に書くには?

    題名のとおりなんですが。 Perlで1~10まで全部足すのに、 1番簡単に書いたらどんな感じなるでしょうか? (一回足すごとに結果は表示) 私は全然浮かばず、 $a = 1 print "$a\n" $b = $a + 1 print "$b\n" $c = $b +2 " …続く こんな感じのお粗末なものを書きました。 whileやforを使えばもっと簡単に書けると思いますが、 どなたかご存知でしたら教えてください。

    • ベストアンサー
    • Perl
  • ハッシュキーの内容について

    こんばんは。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