• ベストアンサー

2次元の配列にデータを格納したい

hoge.txtの様なファイルがあって、この値を2次元の配列に格納したいのですが、簡単に実現することは可能でしょうか? open (FILE, "hoge.txt"); foreach (<FILE>) { # この中で、2次元の配列に格納したい } hoge.txt A  1 B  2 C  3

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

  • ベストアンサー
  • leaz024
  • ベストアンサー率75% (398/526)
回答No.3

> ただ、作成しているものがどうしてもうまくいきません。 どう「うまくいかない」のか、がないのですが、スクリプトを解析して問題点を指摘して欲しい、ということでしょうか、、、 補足に書かれたスクリプトの問題点を挙げますので、参考にしてみてください。 ・コンストラクタで IO::File を使っているが、use していない。 ・get_rows の先頭と main 先頭での変数への代入式が誤っている。それぞれ   my($this)->shift;      ↓   my($this) = shift;   my($tbl)->new Table "File";      ↓   my($tbl) = new Table "File"; ちなみに、get_rows のように引数が複数ある関数では、   my ($this,$index,$key) = @_; と書くことができます。 ・オブジェクトの生成で、data の持ち方がおかしい(これが一番問題)。   "data" => "@data", では、$tbl->{data} の内容は「リファレンス値を列挙した文字列」になってしまいます。ここでは配列データを持たせるべきなので   "data" => \@data, とします。ダブルクォートは付けてはいけません。 こうすると、$tbl->get_data の戻値もリファレンスになるので、受け取る側は   my $data = $tbl->get_data; のようにし、各要素へのアクセスは、   $data->[$row][$col] のようにします。 まずはリファレンスについての理解を深めることを勧めます。 リファレンスについてのドキュメント  http://www.kt.rim.or.jp/~kbk/perl5.005/perlref.html 2次元配列の扱いに関するドキュメント  http://www.kt.rim.or.jp/~kbk/perl5.005/perllol.html

参考URL:
http://www.kt.rim.or.jp/~kbk/perl5.005/perlref.html,http://www.kt.rim.or.jp/~kbk/perl5.005/perllol.html

その他の回答 (2)

  • leaz024
  • ベストアンサー率75% (398/526)
回答No.2

> 行数と列数を@dataから取得する方法があればおしえてください。 行数は   $rows = @data; 列数は   $cols = @{$data[0]}; で取得できます。 ただし、「列」の部分については「無名配列」を使って動的に生成しているので、ファイル内容に不備があると、行ごとの列数が一定でなくなってしまいます。 例えば、万が一   hoge.txt   A  1   B  2 7   C  3 なんてことになっていたりすると、2次元配列の内容も同じように   行\列 0 1 2   0    A  1 なし(列数2)   1    B  2  7 (列数3)   2    C  3 なし(列数2) のようになってしまいますので、ファイルの生成には注意が必要です。 ※Perlには、C言語などのような「完全な2次元配列」を定義する方法がなく、「配列の各要素に別の配列を割り当てる」という方法で実現しているため、このような問題が起こり得ます。

tomoremo
質問者

補足

どうもありがとうございます。 ただ、作成しているものがどうしてもうまくいきません。ご助言いただければうれしいです。 2次元のテーブルファイルから全ての行を取得したり、指定した行を取り出すようなクラスを作りたいと思っています。new()では、指定したファイルのデータを全て2次元の配列に格納します。そして、メソッドでnew()で格納したデータを取得して処理をしたり、指定行を取り出すといった処理をしようと思います。しかし、sub側やmain側でnew()で格納したデータの値を取得することができません。 例えば package Table; #コンストラクタでは、指定したファイルをオープンしてデータを2次元の配列に格納しておきます。 sub new { my($this) = shift; my($file) = shift; my(@data) = (); my($rows) = 0; my($cols) = 0; my($fh) = new IO::File; if ($fh->open("$file")) { while (<$fh>) { chomp; push @data, [ split /\s+/ ]; } $fh->close; } else { エラー処理 } $rows = @data; $cols = @{$data[0]}; my($tbl) = {"name" => "$file", "data" => "@data", "rows" => "$rows", "cols" => "$cols"}; bless $tbl, $this; } #get_data()でデータを取得する sub get_data(){ my($this) = shift; return $this->{data} } sub get_rows() { my($this)->shift; my($indx) = shift;   my($key) = shift; #$this->{data}から値を検索したいが$this->{data}からうまく値を取得できない。 } package main; my($tbl)->new Table "File"; my(@data) = $tbl->get_data(); #@dataを使って行ごとの処理とか指定した列の値を使って処理したい。

  • leaz024
  • ベストアンサー率75% (398/526)
回答No.1

可能です。下記サンプルをお試しください。 open FILE, "hoge.txt" or die 'ファイルが開けません。'; @data = (); while (<FILE>) {   chomp;   push @data, [ split /\s+/ ]; } close FILE; print $data[0][0];  # A print $data[0][1];  # 1 print $data[1][0];  # B print $data[1][1];  # 2 ・ファイルの読み込みでは、foreach ではなく、while を使います。foreach でも出来なくはないのですが、効率がよくありません。 ・while (<FILE>) で読み込んだデータは、特殊変数 $_ に入ります。引数を指定しない chomp や split では、この $_ が対象となります。 ・[ split /\s+/ ] では、空白区切りで分割したデータのリストを初期値として、無名配列を生成しています。配列の要素が配列となるので、2次元配列として使用することが出来ます。

tomoremo
質問者

補足

ありがとうございます。 追加で申し訳ないですが、行数と列数を@dataから取得する方法があればおしえてください。

関連するQ&A