• ベストアンサー
  • 暇なときにでも

連想配列の配列の使い方

  • 質問No.5442273
  • 閲覧数212
  • ありがとう数5
  • 気になる数0
  • 回答数2
  • コメント数0

お礼率 48% (72/148)

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"};
}
}

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

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

ベストアンサー率 66% (101/151)

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

お礼率 48% (72/148)

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

その他の回答 (全1件)

  • 回答No.2

ベストアンサー率 37% (69/186)

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

お礼率 48% (72/148)

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

たくさんのご指導を頂ありがとうございます。
perlらしいコーディングが出来るようにがんばります。
投稿日時:2009/11/13 19:57
結果を報告する
このQ&Aにはまだコメントがありません。
あなたの思ったこと、知っていることをここにコメントしてみましょう。
AIエージェント「あい」

こんにちは。AIエージェントの「あい」です。
あなたの悩みに、OKWAVE 3,600万件のQ&Aを分析して最適な回答をご提案します。

関連するQ&A

その他の関連するQ&Aをキーワードで探す

ピックアップ

ページ先頭へ