blog20100901

2013/08/20 - プログラミング言語 Perl にまつわる etc. - Perl monger
参考 : perldoc, perldoc.jp, search.cpan.org, perldoc.perl.org ...
「 初めての Perl 第 6 版 」(オライリー・ジャパン発行 ISBN978-4-87311-567-2) 」
「 続・初めての Perl 改訂版 」(オライリー・ジャパン発行 ISBN4-87311-305-9) 」
「 Effective Perl 第 2 版 」(翔泳社発行 ISBN978-4-7981-3981-4) 」 ... etc,.

Perl Perl_5 リファレンス

Perl リファレンス 15 データ構造 ハッシュのハッシュ (d018)

Perl リファレンス 15 データ構造 ハッシュのハッシュ (d018)

目次 - Perl Index



Theme



Perl について、復習を兼ねて断片的な情報を掲載して行く連載その d018 回。

Perl で、perldsc - perldoc.jp で解説されているデータ構造から「 ハッシュのハッシュ 」の生成とアクセスの方法を確認する。


 ・ ハッシュのハッシュ
 ・ [ 生成 ] ファイルからの読み込みによる生成
 ・ [ 生成 ] サブルーチンの呼び出しによる生成
 ・ [ 生成 ] 既存のハッシュのハッシュに key/value を追加
 ・ [ アクセス ] ハッシュのハッシュ value にアクセス
 ・ [ アクセス ] ハッシュ全体を一度に出力
 ・ [ アクセス ] ハッシュ全体をソートして出力
 ・ [ アクセス ] ハッシュ全体をメンバーの数でソートして出力
 ・ [ アクセス ] key にランクを設定してソートする


ハッシュのハッシュ



「 ハッシュのハッシュ 」( Hash of Hash : HoH ) は次のような構造です。


%HoH = (
key00 => {
kv00 => "v00",
kv01 => "v01",
},
key10 => {
kv10 => "v10",
kv11 => "v11",
kv12 => "v12",
},
key20 => {
kv20 => "v20",
kv21 => "v21",
},
);




[ 生成 ] ファイルからの読み込みによる生成



外部ファイルを読み込んで、その各行をハッシュ key/value としてハッシュの key に格納する方法を確認します。


# reading from file
# flintstones: lead=fred pal=barney wife=wilma pet=dino
while( <> ){
next unless s/^(.*?):\s*//;
my $who = $1;
foreach my $field ( split ){
my ($key, $value) = split /=/, $field;
$HoH{$who}{$key} = $value;
}
}



一時変数をもう少し利用して同様の処理も可能です。


# reading from file; more temps
while( <> ){
next unless s/^(.*?):\s*//;
my $who = $1;
my $rec = {};
$HoH{$who} = $rec;
foreach my $field ( split ){
my ($key, $value) = split /=/, $field;
$rec->{$key} = $value;
}
}



これは、(d017) で確認したデータ構造「 ハッシュの配列 」( Array of Hash ) の生成とほとんど同じです。

動作確認のために次のテキストファイルを準備しました。


Zenam: Son=Bellri Mother=Wilmit

Surugan: Daughter=Aida Father=Gusion

Megafauna: Captains=Donyell Mechanic=Happa Helmsman=Steer Bridge-Chief=Gisela



これを上記コードで処理すると、次のデータ構造が得られます。


use Data::Dumper;
print Dumper \%HoH;

__END__
# ハッシュのハッシュ
$VAR1 = {
'Zenam' => {
'Son' => 'Bellri',
'Mother' => 'Wilmit'
},
'Meafauna' => {
'Helmsman' => 'Steer',
'Mechanic' => 'Happa',
'Bridge-Chief' => 'Gisela',
'Captains' => 'Donyell'
},
'Surugan' => {
'Father' => 'Gusion',
'Daughter' => 'Aida'
}
};




[ 生成 ] サブルーチンの呼び出しによる生成



サブルーチンの戻り値を直接無名ハッシュとしてハッシュの key/value として格納する方法を確認します。


# calling a function that returns a key,value hash
foreach my $group ( "simpsons", "jetsons", "flintstones" ){
$HoH{$group} = { get_family($group) };
}



同様の処理は、次のように一時変数を利用して行うこともできます。


# likewise, but using temps
foreach my $group ( "simpsons", "jetsons", "flintstones" ){
my %members = get_family($group);
$HoH{$group} = { %members };
}



これは、(d016) で「 配列のハッシュ 」( Hash of Array ) を生成した処理とほとんど同じで、 最終的にハッシュに格納する際に無名ハッシュコンストラクタ「 { } 」を利用している部分が異なります。


sub get_family {
my $group = shift;
if( $group eq 'Zenam' ){
qw/Son Bellri Mother Wilmit/;
}elsif( $group eq 'Surugan' ){
qw/Daughter Aida Father Gusion/;
}
}

my %HoH;
foreach my $group ( "Zenam", "Surugan" ){
$HoH{$group} = { get_family($group) };
}



サブルーチンが返す値は、単なる文字列リストですが、無名ハッシュコンストラクタ「 { } 」によって順番に key/value として設定され、「 ハッシュのハッシュ 」が生成されます。

無名配列コンストラクタ「 [ ] 」を代わりに使うと「 配列のハッシュ 」が生成できます。

ハッシュ「 %HoH 」のデータ構造は次のようになります。


use Data::Dumper;
print Dumper \%HoH;

__END__
$VAR1 = {
'Zenam' => {
'Son' => 'Bellri',
'Mother' => 'Wilmit'
},
'Surugan' => {
'Father' => 'Gusion',
'Daughter' => 'Aida'
}
};




[ 生成 ] 既存のハッシュのハッシュに key/value を追加



既にハッシュのハッシュが設定されたハッシュに新たな key/value を追加する方法を確認します。

ハッシュのハッシュにハッシュを追加したいので、追加のための一時変数にもハッシュを利用すると便利なようです。


# append new members to an existing family
%new_folks = (
wife => "wilma",
pet => "dino",
);

foreach my $what ( keys %new_folks ){
$HoH{flintstones}{$what} = $new_folks{$what};
}



例えば次のようなコードを実行すると、


my %new_folks = (
Friend => 'Nored',
Instructor => 'Dellensen',
);

foreach my $what (keys %new_folks){
$HoH{Zenam}{$what} = $new_folks{$what};
}



データ構造は次のようになります。


use Data::Dumper;
print Dumper \%HoH;

__END__
$VAR1 = {
'Zenam' => {
'Friend' => 'Nored',
'Son' => 'Bellri',
'Mother' => 'Wilmit',
'Instructor' => 'Dellensen'
},
'Surugan' => {
'Father' => 'Gusion',
'Daughter' => 'Aida'
}
};




[ アクセス ] ハッシュのハッシュ value にアクセス



ハッシュ「 %HoH 」の value にセットした無名ハッシュの value にアクセスするには、次の記法が利用可能です。


# one element
${$HoH{Zenam}}{Son}
$HoH{Zenam}->{Son}
$HoH{Zenam}{Son}



別の value にアクセスしたい場合は、ハッシュの key を操作します。


# another element
$HoH{simpsons}{lead} =~ s/(\w)/\u$1/;




[ アクセス ] ハッシュ全体を一度に出力



ハッシュ「 %HoH 」に格納した各ハッシュの全体を出力するには、次のように記述します。


# print the whole thing
foreach my $family ( keys %HoH ){
print "$family: { ";
foreach my $role ( keys %{ $HoH{$family} } ){
print "$role=$HoH{$family}{$role} ";
}
print "}\n";
}



このコードでは、例えば次のような出力が得られます。


Zenam: { Son=Bellri Mother=Wilmit }
Surugan: { Father=Gusion Daughter=Aida }




[ アクセス ] ハッシュ全体をソートして出力



ハッシュ全体をそれなりにソートして出力するには、次のように記述します。


# print the whole thing somewhat sorted
foreach my $family ( sort keys %HoH ){
print "$family: { ";
foreach my $role ( sort keys %{ $HoH{$family} } ){
print "$role=$HoH{$family}{$role} ";
}
print "}\n";
}



親のハッシュ「 %HoH 」と子のハッシュ「 %{ $HoH{$family} } 」の key を取り出す際に、「 keys 」と合わせて「 sort 」を利用することで、それなりに value のソートを行っています。

このコードでは、例えば次のような出力が得られます。


Surugan: { Daughter=Aida Father=Gusion }
Zenam: { Mother=Wilmit Son=Bellri }



前項の出力と比較すると、確かにそれなりのソートが行われていることがわかります。


[ アクセス ] ハッシュ全体をメンバーの数でソートして出力



ハッシュ全体をメンバーの数で比較して多い順 ( 降順 ) でソートして出力するには、次のように記述します。


# print the whole thing sorted by number of members
foreach my $family (
sort{ keys %{$HoH{$b}} <=> keys %{$HoH{$a}} } keys %HoH)
{
print "$family: { ";
foreach my $role ( sort keys %{$HoH{$family}} ){
print "$role=$HoH{$family}{$role} ";
}
print "}\n";
}



このコードでは、例えば次のような出力が得られます。


Zenam: { Friend=Nored Instructor=Dellensen Mother=Wilmit Son=Bellri }
Surugan: { Daughter=Aida Father=Gusion }



メンバー数 ( key/value ) の多いハッシュから順に出力されていることがわかります。スペースシップ演算子「 <=> 」を利用したソートは (d016) の「 配列のハッシュ 」でも利用しました。


[ アクセス ] key にランクを設定してソートする



予めソートする際の順番 ( ランク ) を設定しておくことで、key を任意の順番で並び替えることができます。


# establish a sort order (rank) for each role
my $i = 0;
foreach (qw(lead wife son daughter pal pet)){ $rank{$_} = ++$i }

# now print the whole thing sorted by number of members
foreach my $family (
sort{ keys %{$HoH{$b}} <=> keys %{$HoH{$a}} } keys %HoH)
{
print "$family: { ";
# and print these according to rank orser
foreach my $role (
sort{ $rank{$a} <=> $rank{$b} } keys %{$HoH{$family}} )
{
print "$role=$HoH{$family}{$role} ";
}
print "}\n";
}



次のようにランクを指定してみます。


my %rank;
my $i = 0;
foreach (qw(Son Daughter Father Mother Friend Instructor)){
$rank{$_} = ++$i }



すると次の結果が得られます。


Zenam: { Son=Bellri Mother=Wilmit Friend=Nored Instructor=Dellensen }
Surugan: { Daughter=Aida Father=Gusion }



ランク付けした通りに key がソートされていることがわかります。


NEXT



次回は、「 複雑なレコード 」のデータ構造を確認します。


参考情報は書籍「 続・初めての Perl 改訂版 」, 「 Effective Perl 第 2 版 」を中心に perldoc, Wikipedia および各 Web サイト。それと詳しい先輩。

目次 - Perl Index



























同じカテゴリー(Perl)の記事
 Perl mp2 翻訳 Web コンテンツ圧縮の FAQ (d228) (2023-10-11 23:49)
 Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227) (2023-05-26 15:41)
 Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226) (2023-05-19 17:05)
 Perl mp2 翻訳 テンプレートシステムの選択 (d225) (2022-08-15 22:23)
 Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224) (2022-06-15 20:43)
 Perl mp2 翻訳 チュートリアル (d223) (2022-06-15 20:42)
上の画像に書かれている文字を入力して下さい
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。

Llama
リャマ
TI-DA
てぃーだブログ
プロフィール
セラ (perlackline)
セラ (perlackline)
QRコード
QRCODE
オーナーへメッセージ

PAGE TOP ▲