foreachについての続きの質問

このQ&Aのポイント
  • foreachについての続きに関する質問です。
  • 特に$KU_REC->{KU_CODE}に値を入れる方法について不明点があります。
  • 文字制限のため全てのコードを表示できませんが、足りない部分があれば追加します。
回答を見る
  • ベストアンサー

No.1316461 foreachについての続き

http://oshiete1.goo.ne.jp/kotaeru.php3?q=1316461 で投稿させていただいた内容の続きです。 いろいろ自分なりに吟味してみたのですが、なかなかしっくりきません。 >ん~, でも $KU_REC->{KU_CODE} = $REC{KU_CODE}; >とかなんとかってコードがないと意味がないような.... おっしゃるとおり上記コードがありました。(すみません。文字数エラーが出てしまったので、わからないところ以降は削除し、一部抜粋させていただいておりました) 場所は if ($flg_find_ku == 1) { (1) push(@BCOL, {}); (2) $KU_REC = $BCOL[$#BCOL]; } の次に $KU_REC->{KU_CODE} = $REC{KU_CODE}; $KU_REC->{KU_NAME} = $REC{KU_NAME}; という形で入っておりました。 ただ、どうして、この値が入ったからといって@BCOLに値が入るのかがわかりません。(正式には参照先が、なのかもしれませんが・・・) $KU_REC->{KU_CODE} = $REC{KU_CODE};とすると $KU_RECt->{KU_CODE} eq $REC{KU_CODE}になることがあるのでしょうか?というか、ログ等の結果から言えばあるはずなのですが、どこで@BCOLに対して値が入るのかわかりません。明示的に値を入れているのはpush(@BCOL, {});だけに見えるのです。裏を返せばpush(@BCOL, {});という記述方法以外で$KU_RECt->{KU_CODE}に値を入れる方法があれば、その表記方法を教えてください。 文字制限に引っかかるため、すべてのコードを表示することはできませんが、また足りないと思われるところがあれば、逐次抜粋しますので、よろしくお願いします。

  • Perl
  • 回答数3
  • ありがとう数3

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

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

@BCOL に対しては, $KU_REC 経由で値を入れています. つまり, (1) push(@BCOL, {}); でプッシュしたハッシュへのリファレンスを (2) $KU_REC = $BCOL[$#BCOL]; で $KU_REC という変数に入れていますので, ここで $KU_REC->{KU_CODE} = $REC{KU_CODE}; $KU_REC->{KU_NAME} = $REC{KU_NAME}; を実行すると (1) でプッシュしたハッシュにデータが入ります. が, だったら最初から push(@BCOL, {KU_CODE => $REC{KU_CODE}, KU_NAME => $REC{KU_NAME}}); とすればいいということになりますが, その後でさらに各データに追加するのかなぁ? さらにいうと, その後の使い方によってはハッシュを使って $BCOL{$REC{KU_CODE}} = $REC{KU_NAME}; とすべきかもしれません.

cshoaucmoa
質問者

お礼

Tacosanさん、いつも的確な答えをありがとうございます。前回と同様、きっと答えていただける、とすごく期待しておりました(~~; さて、今回の件、前回より何度考えてもわからなくて、でも漠然とはそうかな、とつかめかけてたのですが、確証がほしくて投稿しました。しかしながら、頭で理解しても感覚としてはまだつかみきれていない状態で、まだまだ壁は厚いです。 なぜ○○しないのかなぁ、という点ですが、私にもいまいちつかめないですが、この後もデータが追加されるのは間違いありません。 push(@{$KU_REC->{BU}}, {}); $BU_REC = $KU_REC->{BU}->[$#{$KU_REC->{BU}}]; を行い、 $BU_REC->{BU_CODE} = $REC{BU_CODE}; $BU_REC->{BU_NAME} = $REC{BU_NAME}; とし、 foreach $BU_RECt (@{$KU_REC->{BU}}) { if ($BU_RECt->{BU_CODE} eq $REC{BU_CODE}) { $BU_REC = $BU_RECt; $flg_find_bu = 0; last; } } として、部コードに関しても同じように行っています。 ここまでくるともはや@BCOLにはどんなデータがどのように並んでいるのかわかりません(*_*)でもそれを解析しなくてはならないのです。 ここでまたまた質問です。@BCOLは配列ですよね? いま$BCOL[0]に{KU_CODE => $REC{KU_CODE}が入っているかと思うのですが、配列内に入っているハッシュのキーと値をログで出力する方法はあるのでしょうか? お礼なのに、質問しちゃってすみません・・・。こういう場合また新しくとぴをたてるほうがいいのかなぁ・・・。 よろしくお願いします。

その他の回答 (2)

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

高速化というよりは (C で言うところの) 構造体を作るためにハッシュを使いたいんだけどハッシュそのものは入れられないのでリファレンスを使っているという感じだと思います. ただ, どうも「なんというか」という感じになったりするわけでして, 例えば対象とする区コードや部コードを見付ける部分はサブルーチンに切り分けた方がいいんじゃないかなと思います. 例えば (このサブルーチンが正しいかどうかは知りませんが) sub findRecord(\@$$) { my ($records, $key, $value) = @_; foreach (@$records) { if ($_->{$key} eq $value) { $target = $_; last; } $target; } とすれば foreach $BU_RECt (@{$KU_REC->{BU}}) { if ($BU_RECt->{BU_CODE} eq $REC{BU_CODE}) { $BU_REC = $BU_RECt; $flg_find_bu = 0; last; } } は $BU_REC = findRecord($KU_REC->{BU}, 'BU_CODE', $REC{BU_CODE}); の 1行ですむ ($flg_find_bu の判定は defined $BU_REC で代用) ので読みやすくなりますよね. 区コードを見付けるところも $KU_REC = findRecord(\@BCOL, 'KU_CODE', $REC{KU_CODE}); と書けますし.

cshoaucmoa
質問者

お礼

おっしゃるとおりですね。私も目が回りそうになるくらい何度もLOOP処理を見ましたが、サブルーチン化できるところは分けたほうが見やすいですね。あとはそうできない理由がないか、ちゃんと見て、できそうならトライしてみようと思います。ありがとうございました。

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

.... なんか, とってもすごいプログラムのような気がしてきました.... プログラムを解析するよりも「やりたいこと」を理解して最初から作り直した方がいいような気もしますが, そうも言ってられないと思いますので簡単に: データを出力したいだけであれば Dumpvalue というモジュールを使うのが最もお手軽だと思います. 気を抜くと全データが出力されて, 見ていられないという問題はありますが. 「@BCOL にはどんなデータがどのように並んでいるか」ですが, まず「どのように並んでいるか」は無視しちゃってかまわないと思います. また, 入っているデータについてはハッシュ (へのリファレンス) であることはわかっているので, そのハッシュでキーと値 (の意味) の対応を見ればいいと思います. つまり, @BCOL の各データは KU_CODE, KU_NAME, BU という 3つのキーを持つハッシュで, それぞれ「区コード」, 「区の名前」, 「その区に入っている部のデータ」に対応します. で, BU についてもやはり同様に順序を無視して入っているデータだけ考えればよいでしょう.

cshoaucmoa
質問者

お礼

迅速な回答ありがとうございます。 でも、なんかだいぶ頭がすっきり整理されてきて、どこに新しい処理を入れなくてはいけないのか、がわかってきました。Dumpvalueをつかってもっと明確にしていきたいとおもいます。 しかし、PERLでは高速化するためにリファレンスを使ってるんだと思いますが、そのおかげでとっても入り組んだものになってしまいますね。わかりにくかったので、その部分だけ(区分、部コードを取得するところ)フローチャートにしてみるとA33枚になってしまいました(^^;

関連するQ&A

  • foreachについて

    ポケットリファレンスより foreach[★](□){■} 配列などの一連のスカラー値を持つリスト□から順に要素を取り出し、スカラー変数★に代入してからブロック内の■を繰り返し実行します。リスト値□がなくなった段階で終了します。 とあります。今解析しているプログラムで下記のようなコードがあり、数点質問があります。(このコードの前にあるDBを呼んで、$RECにデータを返しています) undef @BCOL; my($KU_REC); while ($rc = $DBr->fetchrow_hashref) { $flg_find_ku = 1; foreach $KU_RECt (@BCOL) { if ($KU_RECt->{KU_CODE} eq $REC{KU_CODE}) { $KU_REC = $KU_RECt; $flg_find_ku = 0; last; } $KU_REC = $KU_RECt; } if ($flg_find_ku == 1) { (1) push(@BCOL, {}); (2) $KU_REC = $BCOL[$#BCOL]; } } (1)@BCOLは最初要素を含んでいないように思うのですが、リファレンスの(リストの値がなくなるまで)という部分をみて疑問ですが、リストに値がないのに、foreachの中をとおるのでしょうか? (2)たとえば、とおったとして、このロジックはおなじ区コードを見つけて、見つかればフラグを0にするという処理だと思うのですが、最初の一回目は(1)(2)をとおると思います。この処理が何をしているかわかりません。@BCOLに{}を入れるとどうなるのでしょうか? また、$#BCOLは配列の引数をあらわしているように見えるのですが、いったい何番目の意味なのでしょうか? (3)スカラー変数は基本的にmyなどで宣言するかと思うのですが、foreachで使われる変数$KU_RECtの定義がみつかりません。ということはこの場合変数定義はいらないものと思ってよいのでしょうか? 私が何か勘違いしている部分もあるかと思うのですが、わかる方、どうぞよろしくお願いいたします。

    • ベストアンサー
    • Perl
  • ある条件のSELECT文の作成について

    以下のSQLの作成で悩んでいます。 【内容】 抽出元テーブルの中で、あるコードが同じデータは、 ある項目を全て同じ値にして取得したい。 (例) ■抽出元テーブル コード SEQ FLG  1    1   1  1    2    1    3    2    1   0  2    2  2    3  3    1   1 コードは同じ物が1つ又は複数あります。 コードが同じ物にはSEQで番号が連番されます。 FLGの項目がありますが、SEQ=1のデータしか設定されていません。 ■求めたい結果 コード SEQ FLG  1    1   1  1    2   1    1    3   1  2    1   0  2    2   0  2    3   0  3    1   1 全てのデータでFLGを求めて取得します。 取得の仕方はコードが同じでSEQ=1の値を取ります。 抽出元テーブルと結果のデータ件数は同じになります。 抽出元テーブルと結果の違いは、FLGに値が埋まっているかどうかの違いのみです。 このテーブルのFLGはUPDATEする事は出来ません。 別表なども利用しないで、 selectのSQL文だけで対応したいです。 どのような方法で対応できるでしょうか? オラクルのバージョンは10gです。 よろしくお願い致します。

  • アンダーバーのname値は取得できないでしょうか?

    Javascriptのname値にアンダーバーは付けない方が 良いのでしょうか? 又、使用した場合、name値を取得する方法はありますか? 値を取得できない例 alert(document.frm1.day_flg.value); 値を取得できる例 alert(document.frm1.dayflg.value); <form name="frm1"> <input type="radio" name="day_flg" value="1" checked> <input type="radio" name="dayflg" value="1" checked> </from>

  • plpgsqlのエスケープ文字について

    plpgsqlのエスケープ文字について教えてください tblのテーブルのnameフィールドの値をtitleフィールドに更新する関数を作成してます。 cur cursor for SELECT id, name FROM tbl; rec RECO RD; begin open cur; LOOP FETCH cur INTO rec; EXIT WHEM NOT FOUND; w_sql := ''UPDAT tbl SET title = ''; w_sql := w_sql ll '' ''''タイトル: '' ll rec.name ll '' '''' ''; w_sql := w_sql ll '' WHERE id= '' ll rec.id= '' ll rec.id ; EXECUTE w_sql; END LOOP; ・ ・ ・ ・ ・ 上記のようにnameフィールドの値をset句に設定していますが、 nameフィールドには 「90's」 や「men's」 のような値が入ったレコードがあるためエラーとなってしまいます。 name内の「'」をエスケープする為にはどのように書けばよいでしょうか 教えてください

  • リストに何も無ければXXを表示…

    あるCGIのログの一部をSSIで表示させようとしています。リストの「pt」と「name」があったものだけを「$max」個表示すると言う物です。 一部抜き出すと… ----- print "Content-Type: text/plain\n\n"; open (FILE,"../../cgi-bin/navi-a/navi.log"); $i=0; while (<FILE>) { local($no,$pt,$sub,$hp,$name,$email,$pw,$msg,$dt,$ts,$rec,$axs) = split(/<>/); if ($pt eq $ARGV[0] && $name eq $ARGV[1]){ $i++; print "~ } if ($i >= $max) { last; } } ----- これに、「合う物が無かったら"無いですよ"文を表示」と言うのを付けたいのですが、うまく出来ません。 if ($pt eq $ARGV[0] && $name eq "") とかを試してみましたがうまく出来ませんでした。 何か良い方法が無いでしょうか? お願いします。

    • ベストアンサー
    • CGI
  • vb ado → vb2005 ado.net変換

    お世話になります。初めて投稿させていただきます。 VB6.0で下記のようなコードでコンボボックスcboMakerへフィールド値を格納しているのですがこのコードをVB2005のado.netで記述したいのですが可能でしょうか?可能であればどのようなコードを書けばよいのでしょうか。フィールドの値を1レコードづつ取得することは可能なのでしょうか? 初心者ですみません。宜しくお願いします。 Dim con As ADODB.Connection Dim rec As ADODB.Recordset Dim sql As String Dim recCnt As Long con = New ADODB.Connection con.ConnectionString "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & パス con.Open() rec = New ADODB.Recordset sql = "SELECT * FROM " & テーブル名 rec.Open(sql, con, adOpenStatic, adLockReadOnly) If rec.RecordCount < 1 Then 'レコードが存在しない MsgBox("未登録です。", G_MB_CAUTION, G_SYSTEM_NAME) Exit Function Else ReDim CboMakerId(rec.RecordCount) End If 'コンボボックスに値を挿入 ※「.List(recCnt)」から値を挿入する With Me.cboMaker .Clear() recCnt = 0 .List(recCnt) = "" .ItemData(recCnt) = 0 Do Until rec.EOF recCnt = recCnt + 1 .List(recCnt) = rec("Name") .ItemData(recCnt) = rec("ID") rec.MoveNext() Loop End With Me.cboMaker.ListIndex = 0 rec.Close() : rec = Nothing con.Close() : rec = Nothing End Function

  • 取得する順番

    mysq初心者です 値の取得する順番を変えないで、値を取得する方法はありますか? 会員IDが5、1、3で取得したいのですが1、3、5に並び替えられてしまいます テーブルはIDとNAMEのみ、重複なしで、ID番号と名前番号が一致しています sprintf('SELECT id FROM hoge2 WHERE name="%s" or name="%s" or name="%s" ', ほげ5, ほげ1, ほげ3 ); $recd = array(); while ($rec = mysql_fetch_assoc($sql2)) { $recd[] =$rec['id']; }

    • ベストアンサー
    • MySQL
  • UPDATEのCASE文で・・

    SQLの独学をはじめて間もない素人です。 今case文を使って・・a_flg、b_flgを更新というコードを考えたのですが・・↓ UPDATE tm_results_payment SET a_flg = ( CASE WHEN b_flg=1 AND a_flg=1 THEN '0' END ) b_flg = ( CASE WHEN b_flg=1 AND a_flg=1 THEN '1' ELSE b_flg END ) CASE文は同じ条件です。値を2個とも変更したいので上の処理を考えました。 しかし、どうやら先に最初のCASE文でa_flgを0に変えてしまっているので、 次のCASE文では処理をしてくれません・・; 同時進行で値を更新する方法ってどうすればよいのでしょうか・・; よろしくお願いいたします。

  • foreachのスコープ

    while(0<$i<count($html)) { foreach($html->find('title') as $title) { global $title; } foreach($html->find('img a')as $url) { global $link=$url->href; $link=mb_convert_encoding($url,"utf8","euc-jp"); var_dump($link);//この変数をスコープ範囲外でDBに登録したい } $db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); $stt=$db->prepare('insert into links(name,url) VALUES(?,?)'); $stt->execute(array($title,$link)); } ------------------------------------------------------------------------- 上記を行いたくコードを記述してましたが$linksの部分に何もなく、DB登録することが出来ませんでした。原因を探すために検索したところ、関数の範囲内の変数のスコープに問題があることがわかりました。外部から内部変数へのアクセス(参照)は不可能なのでしょうか?現在のままだと「$url」が文字列ではない状態なので登録できないと考えております。事実文字列の「$title」はDBに登録出来るのですが$linkのみ値が何も入ってない状態で登録されてしまいます。 スコープの範囲内であれば当然var_dump($link)は表示されます。 使ってるライブラリは「simple html dom parser」で、抽出は完了しています。 この「$link」というのは文字列ではない状態なので文字列変換させる関数に直せばDB登録できるのでしょうか?それならばstrvalまたは__toString関数を他に作っておいてそれを使えば可能なのでしょうか? どなたかご教授頂けませんでしょうか?

    • 締切済み
    • PHP
  • 同じname属性の結果を1行にまとめる方法

    いつもお世話になっている者です。フォームメールCGIで行き詰っております。 push(@DATA_KS,$name); push(@DATA_VS,$value); としてHTML側のname属性を@DATA_KSに、valueの値を@DATA_VSに代入しています。 <table border=0 cellpadding=3 cellspacing=1 bgcolor="#ffffff"> <tr><td bgcolor="#ff8000"><b><font size=+1>項目</font></b></td><td bgcolor="#ff8000"><b><font size=+1>内容</font></b></td></tr> EOF $count = @DATA_KS; foreach (0..$count-1) { print "<input type=hidden name=\"$DATA_KS[($_)]\" value=\"$DATA_VS[($_)]\">\n"; if ($DATA_VS[($_)] eq '') {} else { print "<td bgcolor=\"#009900\">$DATA_KS[($_)]</td>\n"; } if ($DATA_VS[($_)] eq '') {} else { print "<td bgcolor=\"#ffffff\">$DATA_VS[($_)]</td>\n"; } print "</td></tr>\n"; } これで 項目 内容 が1セットで横並びになり項目の数だけ下に続き、値の無い項目は表示されない。というところまでは出来たのですが さらに「name属性が同じ場合はvalueの値をカンマで区切ってヨコに並べる」ということがしたいのですが方法が分かりません。何卒宜しくお願いします。 例:  ○(希望表示方法) 好きな食べ物  りんご,ハチミツ,カレー × 好きな食べ物  りんご 好きな食べ物  ハチミツ 好きな食べ物  カレー

    • ベストアンサー
    • CGI

専門家に質問してみよう