• ベストアンサー

連想配列の配列の使い方

C言語でいうところの構造体の配列(要素は"hoge"と"fuga"のみ)を perlで表現する場合、連想配列の配列にするのが一般的でしょうか? 以下の様なソースコードなのですが、perlらしさが失われている気がします。 perlらしく書くとしたらどう書くのが良いでしょうか? [ソース] @list; #この配列の要素に連想配列を入れる sub input{ #list.txtの中にはhogeとfugaの値がカンマ区切りで記入されている open(IN, "list.txt");  $i = 0; while ($xx = <IN>) { ($list[$i]{"hoge"}, $list[$i]{"fuga"}) = split /,/, $xx; $i++; } close(IN); } sub output{ for($i = 0; $i <= $#list; $i++){ print $list[$i]{"hoge"}, $list[$i]{"fuga"}; } }

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

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

  • ベストアンサー
回答No.1

Perl らしいかどうかは別にして、 use strict; use warnings; my @list = (); while ( defined( my $line = <DATA> ) ) { $line =~ s/\x0D?\x0A?$//; # my chomp if ( $line =~ /^([^,]+),([^,]+)/ ) { push @list, { hoge => $1, fuga => $2 }; } } for my $hash_ref (@list) { print "hoge = ", $hash_ref->{hoge}, ", fuga = ", $hash_ref->{fuga}, "\n"; } __DATA__ aaa,bbb,ccc 111,222,333 AB,CD,EF

sora_naegino
質問者

お礼

ご回答ありがとうございます。 C言語出身だと馴染みの無い文字列の置換やforの書き方がperlらしいですね。 大変参考になりました。

その他の回答 (1)

  • ryu_chan
  • ベストアンサー率37% (69/186)
回答No.2

Perlはまだまだ勉強中の者ですが、私の知っている知識を書きたいと思います。 既知のものがありましたら、ごめんなさい。 データの構造は、その後、どのような使い方をするかで決まると思いますので何 とも言えないのですが、現状で特に問題ないように見えます。 1.use strict; use warnings; No.1さんも書かれていますが、バグを未然に防いで(特にtypo)くれるので、 これは必須です。 2.open関数 open関数で使うファイルハンドル変数は、質問者さんのようにINとしてしまうと、 グローバル変数となるので、レキシカル変数を使うほうがベターです。 また、エラーのときの処理も書いておいたほうがいいです。 エラーのトラップは、or die とするのがPerlの慣例のようです。 open my $in, 'list.txt' or die $!; モードを指定するときで、かつファイル名が変数の場合、脆弱性を排除できるの で3引数にしたほうがいいです(CGI等で使う場合ですが)。 3引数ならエンコーディングの指定もできます。 × open my $fh, "<$file" or die $!; ○ open my $fh, '<', $file or die $!; ○ open my $fh, '<:encoding(euc-jp)', $file or die $!; 3.for文 for文は、質問者さんが書かれているC風な書き方よりは、No.1さんが書かれてい るような書き方のほうが、よりPerlらしい感じがします。 for($i = 0; $i <= $#list; $i++){    ↓   ↓ for my $i ( 0..$#list ) { もちろん、C風に書いたほうがいい場合もあると思います。 4、ファイルからの1行づつのデータ読み込み ファイルから読み込んだ1行データには、$lineという変数名をつけることが多い ようです。もちろん、もっと意味のある変数名にするほうがベターですが。 データを読み込んだら、改行除去のchompをするのを忘れずに。 下記のように、$_を利用する人もいますが、可読性が下がるので、ワンライナー や使い捨てスクリプト以外ではあまり使わないほういいとされているようです。 while ( <$in> ) { chomp #下のsplitの区切り正規表現のデフォルトが/\s+/なので、この場合は省略可 my @data = split;     ・     ・ } 一例として、以下のように書いてみました。 use strict; use warnings; my @list = input(); output(@list); # デバッグでデータ階層の深い変数を見るときは、こうすると一覧表示してくれ # ます use Data::Dumper; print Dumper \@list; sub input { open my $in, 'data.txt' or die $!; my @list; while ( my $line = <$in> ) { chomp $line; my %hash; @hash{ qw(hoge fuga) } = split /,/, $line; push @list, \%hash; } close $in or die $!; return @list; } sub output { my @list = @_; # ちょっとややこしくなりましたが、hoge、fugaといった具体名が出ないように # 抽象化してみました for my $hash_ref (@list) { my @data_str = map "$_ = $hash_ref->{$_}", sort keys %$hash_ref; print join( q{, }, @data_str ), "\n"; } }

sora_naegino
質問者

お礼

たくさんの解説とサンプルソースまで書いていただいて本当にありがとうございます。 大文字のINだとstdinみたいな標準のファイルディスクリプタみたいな扱いになるのかな・・・? ちょっと調べておこうと思います。 プラグマは存在は知っていたのですが、面倒だったので付けていませんでした。 open関数の使い方は参考にしたURLをそのまま使ったので良く分かっていませんでした。 open関数の仕様とエラートラップの使い方も調べておこうと思います。 たくさんのご指導を頂ありがとうございます。 perlらしいコーディングが出来るようにがんばります。

関連するQ&A

  • 配列を回すとき、最後の要素だけ違う処理をしたい

    hoge[0]に対して、配列の中身を処理して, 最後にカンマを付与 hoge[1]に対して、配列の中身を処理して, 最後にカンマを付与 hoge[2]に対して、配列の中身を処理して, 最後にカンマを付与 hoge[3]に対して、配列の中身を処理して, 最後にカンマを付与しない というようなことをするとき、 どう書けばよいでしょうか? for ($i = 0 ; $i <count($hoge); $i++) {   if($i< count($hoge)-1){    //配列の要素が最後じゃないのに対する処理     .",";  }else{    //配列の要素が最後のに対する処理  } } ってしたら、とりあえず、動いたのですが、 普通はどういう風に書くのでしょうか? foreachとか、あるいは、配列の最後に対してする何か 書き方ってあるのでしょうか

    • ベストアンサー
    • PHP
  • 配列や連想配列について

    言語一般の配列や連想配列について 最近どういう解釈をしていいのか わからなくなってしまいました。 仮にPerlで話をさせてもらいますと、 連想配列%FORMがあるとき、 個々の要素にアクセスする場合 例えば$FORM{'name'}などと記述しますが、 この$FORM{'name'}を みなさんはどのように解釈しているでしょうか? $FORM{' '}にキー nameを 代入しているようなイメージで、 「連想配列%FORMからキー'name'の値を取得する」 という考え方でしょうか? わたしは最近、 $FORM{'name'}はそれ自体が一つの変数という 考え方が出来るのではないかという気がしているのですが、 連想配列の実装から考えると この考え方は正しいのでしょうか? 以前、配列について同様の質問を したことがあります。 例えばC言語でint a[100]と宣言した場合は、 連続的なアドレスに確保されるため、 a[2]はaという名前のアドレスから a + 2 番目の場所という意味になるが、 言語によっては不連続なアドレスに 確保されるため、a[2]は一つの変数名として 考える必要がある・・ との回答でした。 ならば連想配列の場合も もし不連続なアドレスに確保されるならば、 $FORM{'name'} は一つの変数名と 考えたほうが正しいのではないかと 思ったからです。 連想配列の内部的な処理がどうなっているのか 教えて頂きたいです。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • Perlのサブルーチンで連想配列(ハッシュ)を渡す

    Perlのサブルーチンで連想配列(ハッシュ)を渡す方法 -------------------------------------- $str=rep::replace(%A,$B,@C); -------------------------------------- sub refidrep ( \%\$\@ ){ my(%A,$B,@C)=(@_); } -------------------------------------- では、上手くいきませんでした。 どのようにしたら、連想配列をサブルーチンに渡せるのでしょうか? 分かる方いらっしゃいましたらご教授ください。

    • ベストアンサー
    • Perl
  • 連想配列の初期化

    UNIXでAWKの連想配列を使っています。 連想配列を処理の途中で初期化したいのですが、どうすれば良いのでしょう? とりあえず今は以下のように初期化をしています。 for ( i in a ){a[i]="";} しかし、できれば a=null という感じに一発で初期化をしたいのです。

  • 関数戻り値が連想配列の場合

    こんにちわ。 PHP5について質問です。 あるユーザ関数の戻り値が連想配列である場合、 ユーザ関数の実行~戻値の特定のキーの値を取得 までを1行で取得する方法があれば教えてください。 例) function hoge() {  return array("fuga" => "1", "moge" => "2"); } ここで"moge"の値を一発で参照したいと考えています。 通常では、 $result = hoge(); print $result["moge"]; のようにしていますが、これを一行で実現できる方法はありますでしょうか。

    • ベストアンサー
    • PHP
  • 配列を用いた文字置換

    初投稿です。よろしくお願いいたします。 kana2phone_rule.txtにはア+aという情報が五十音で入っています。01.txt.chaには愛+アイという情報が入っています。 以下のプログラムは01.txt.chaのプラスの後の要素 (アイ)を音表記(ai)に変換するというものです。 しかし変換の作業が行われない(アイ)ままファイルを吐き出してしまいます。 文字コードはEUC、改行コードLFで試しても、Jperlを用いてShift-JIS、CR+LFで試してもだめでした。 どこに問題があるのでしょうか。 分かりましたらよろしくお願いいたします。 open(IN,"kana2phone_rule.txt"); $j = 0; while($b=<IN>){ chomp $b; @list = split(/\+/, "$b"); $kana[$j] = "$list[0]"; $yomi[$j] = "$list[1]"; $j++; } close(IN); open(IN, "01.txt.cha"); open(OUT, "> kekka.txt"); while($a=<IN>){ chomp $a; @list2 = split(/\+/, "$a"); for($i=0; $i<=258; $i++){ $list2[1] = ~s/$kana[$i]/$yomi[$i]/g; } print OUT "$a [$list2[0]] $list2[1]\n"; } close(IN); close(OUT);

    • ベストアンサー
    • Perl
  • 配列に動的に連想配列を入れる方法を教えてください

    質問させてください。 $mods = array('def', 'con', 'vie'); (ここでは$modsの要素は3つですが、環境によって要素の数が変わるとします。) これを連想配列で array( 'def' => './a/b/def/o', 'con' => './a/b/con/o', 'vie' => './a/b/vie/o' ) のような形に動的にしたいと思います。 その為 array( $mods[$i] => './a/b/' . $mod[$i] . '/o', ) のように$modsの要素数だけ動的に入れていきたいのですがどのようにすればいいのでしょうか? array_push()だと値だけが入ると思うので、良く分かりませんでした。 $front->setControllerDirectory(array( 'default' => APP_DIR . DS . 'modules' . DS . 'default' . DS . 'controllers' )); のようなルーターにパスをその時の環境に合わせて$key=>$valueの連想配列をどんどん入れていきたいと考えております。 説明が分かりにくいかもしれませんが宜しくお願いします。

    • ベストアンサー
    • PHP
  • 配列から効率よくマッチさせるには

    配列からなるべく高速にマッチさせたいと思っているのですが、 たとえば、以下のようにリストをlist.datへ保存させている場合で キーワード1<>filename1<>time1<> キーワード2<>filename2<>time2<> フォームから入力されたキーワードとマッチさせてfilenameの要素を 取り出すといった場合、通常の配列ループを利用すると open(IN,"list.dat"); while (<IN>) { ($key,$name,$time) = split(/<>/); if($FORM{'key'} eq $key) { last; } } のようにしてフォームで入力したものとマッチさせるような 形になると思いますが、連想配列と言うものを活用すると もっと効率よく高速に処理できるのでしょうか? もしよろしければ出来る限り効率の良い方法(ソース)を 教えていただけましたら幸いです。

    • ベストアンサー
    • Perl
  • C# 配列の配列(多次元配列?)

    C#において、配列の配列中に格納した値を、検索することを 行いたいのですが、格納した値そのものを見ることができません。 まだ、C#を始めて間もないので、配列に格納する時点で、 不備があるかも知れませんが、お願いします。 やりたいこと ・テキストファイル内にある値を、2次元配列または、多次元配列に格納 ・配列に格納した値で、データチェックなどを行う予定  テキストファイル内のデータは、下記内容となり要素数も固定ではなく変動する   A=1,2,3・・・   B=11,22,33・・・ 実際のソースは、 //配列 ArrayList list = new ArrayList(); //配列格納 1レコード毎用 ArrayList listtmp = new ArrayList(); while ((strGenderTextLine = objReader.ReadLine()) != null) {  string strBuffer;  //「=」前の値格納用変数  string[] strBuffer2; //「=」後の値格納用配列  listtmp=null;  //strtmpに「=」前の値を格納  strtmp = TextLine.Split('=').GetValue(0).ToString();  //strtmp2に「=」後の値を格納(配列)  strtmp2 = TextLine.Split('=').GetValue(1).ToString().Split(',');  for (int i = 0; i <= strtmp2.Length - 1; i ++)  {   //[i,0]に、「=」前の値を代入   if (i == 0)   {   listtmp.Add(strtmp);   }   else   {   listtmp.Add(strtmp2[i].ToString());   }  }  //list配列にlistTmp配列を格納(配列の配列)  list.Add(listtmp);  intT = intT + strtmp2.Length;  //行数カウント  intTLine = intTLine + 1;  } ここから、配列「list」内に入っている値を閲覧することができる方法を教えていただければと思います。 宜しくお願いいたします。

  • VBA 連想配列と回数

    Widowsは7 Excelは2013を使用しています。 E列のデータの重複しないリストをK列に書きだすところまでは出来たのですが、 同じ商品名が何回出てきたをカウントしたいのですが、 下記の連想配列で一緒に出来るのか、分けて組まないといけないのか、 教えて下さい。 よろしくお願い致します。 '---------------------------- '重複しないリストをK列に書き出す '---------------------------- Dim Dic, i As Long, buf As String, Keys Set Dic = CreateObject("Scripting.Dictionary") For i = 2 To maxRow buf = Cells(i, 5).Value 'E列のセルの値をbufに格納する If Not Dic.Exists(buf) Then '辞書にまだ登録されていなければ Dic.Add buf, buf 'そのセルの値を連想配列に登録する。 End If Next i '出力 Keys = Dic.Keys For i = 0 To Dic.Count - 1 Cells(i + 2, 11) = Keys(i) 'K2から下にリスト作成 Next i Set Dic = Nothing End Sub

専門家に質問してみよう