- ベストアンサー
2次元の配列にデータを格納したい
hoge.txtの様なファイルがあって、この値を2次元の配列に格納したいのですが、簡単に実現することは可能でしょうか? open (FILE, "hoge.txt"); foreach (<FILE>) { # この中で、2次元の配列に格納したい } hoge.txt A 1 B 2 C 3
- みんなの回答 (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
その他の回答 (2)
- leaz024
- ベストアンサー率75% (398/526)
> 行数と列数を@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次元配列」を定義する方法がなく、「配列の各要素に別の配列を割り当てる」という方法で実現しているため、このような問題が起こり得ます。
- leaz024
- ベストアンサー率75% (398/526)
可能です。下記サンプルをお試しください。 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次元配列として使用することが出来ます。
補足
ありがとうございます。 追加で申し訳ないですが、行数と列数を@dataから取得する方法があればおしえてください。
補足
どうもありがとうございます。 ただ、作成しているものがどうしてもうまくいきません。ご助言いただければうれしいです。 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を使って行ごとの処理とか指定した列の値を使って処理したい。