ルモーリン
ホーム 更新 Perl Sample サービス 雑談 鉄ゲタ Linux リンク 連絡先

Perlサンプル8 階層構造を持つデータ

2019-08-29

内容

「フォルダ→ファイル名→ファイルの中身」といった階層構造を持つデータをリテラルで書きます。 CPANにあるモジュールに複雑なデータを受け渡す際に使いますので覚えておきましょう。

階層構造

ハッシュのリファレンスと配列のリファレンスを組み合わせて使います。 ハッシュはキー/値のセット、キー順は不同、キー重複がありません。 配列は値だけ、順序は変わらず、重複あります。 階層構造の表現方法は今適当に思いついたので元ネタはありません。 たこルカ4人とルカ姐さん7人で構成された世界です。

world ┬ たこルカぬいぐるみ_肩のりサイズ ─[0]┬ name ─ たこルカ1号
      │                                   │ └ kind ─ ほほえみ顔
      │                                   │
      │                                   [1]┬ name ─ たこルカ2号
      │                                   │ └ kind ─ きゃー顔
      │                                   │
      │                                   [2]┬ name ─ たこルカ3号
      │                                   │ └ kind ─ よだれ顔
      │                                   │
      │                                   [3]┬ name ─ たこルカ4号
      │                                      └ kind ─ おすまし顔
      │
      └ ルカ姐さん_ぬいぐるみ ─[0]┬ name ─ ルカ姐さん
                                 │ └ kind ─ キーホルダー
                                 │
                                 [1]┬ name ─ ルカ姐さん
                                 │ └ kind ─ キーホルダー
                                 │
                                 [2]┬ name ─ ルカ姐さん
                                 │ └ kind ─ キーホルダー
                                 │
                                 [3]┬ name ─ ルカ姐さん
                                 │ └ kind ─ ジャンボぬいぐるみ
                                 │
                                 [4]┬ name ─ ルカ姐さん
                                 │ └ kind ─ ジャンボぬいぐるみ
                                 │
                                 [5]┬ name ─ ルカ姐さん
                                 │ └ kind ─ ジャンボぬいぐるみ
                                 │
                                 [6]┬ name ─ ルカ姐さん
                                    └ kind ─ ジャンボぬいぐるみ

コード

#!/usr/bin/env perl

use v5.26;
use utf8;
use strict;
use warnings;

use Encode::Argv;
use Encode::Locale;

use open IO => ":utf8";
binmode STDIN, ":encoding(console_in)";
binmode STDOUT, ":encoding(console_out)";

$| = 1;

my $world = {
	たこルカぬいぐるみ_肩のりサイズ => [
		{ name => "たこルカ1号", kind => "ほほえみ顔", },
		{ name => "たこルカ2号", kind => "きゃー顔", },
		{ name => "たこルカ3号", kind => "よだれ顔", },
		{ name => "たこルカ4号", kind => "おすまし顔", },
	],
	ルカ姐さん_ぬいぐるみ => [
		{ name => "ルカ姐さん", kind => "キーホルダー", },
		{ name => "ルカ姐さん", kind => "キーホルダー", },
		{ name => "ルカ姐さん", kind => "キーホルダー", },
		{ name => "ルカ姐さん", kind => "ジャンボぬいぐるみ", },
		{ name => "ルカ姐さん", kind => "ジャンボぬいぐるみ", },
		{ name => "ルカ姐さん", kind => "ジャンボぬいぐるみ", },
		{ name => "ルカ姐さん", kind => "ジャンボぬいぐるみ", },
	],
};

say "世界の構成";
say "-----";

for (keys %{$world}) {
	say;
	say "$_->{name}, $_->{kind}" for @{$world->{$_}};
	say "-----";
}

実行結果

「たこルカぬいぐるみ_肩のりサイズ」と「ルカ姐さん_ぬいぐるみ」はハッシュのキーですから順不同です。 たこルカ1号~4号の順、キーホルダーとジャンボぬいぐるみは配列ですから常にこの順序です。

世界の構成
-----
たこルカぬいぐるみ_肩のりサイズ
たこルカ1号, ほほえみ顔
たこルカ2号, きゃー顔
たこルカ3号, よだれ顔
たこルカ4号, おすまし顔
-----
ルカ姐さん_ぬいぐるみ
ルカ姐さん, キーホルダー
ルカ姐さん, キーホルダー
ルカ姐さん, キーホルダー
ルカ姐さん, ジャンボぬいぐるみ
ルカ姐さん, ジャンボぬいぐるみ
ルカ姐さん, ジャンボぬいぐるみ
ルカ姐さん, ジャンボぬいぐるみ
-----

解説

{~}

ハッシュのリファレンスです。 中カッコの中身は2個一組のキー/値のセットです。 「=>」はファットカンマですからキーを「''」で囲めば「=>」の代わりに「,」を使えます。 あとファットカンマにしておけば、もしかしてハッシュかもと予想できます。 もちろん、Perlのことなので、カンマ代わりにファットカンマを使っても差し支えありません。

[~]

配列のリファレンスです。 大カッコの中身がそのまま配列になります。

%{$world}

$worldはハッシュのリファレンスです。 これをデリファレンスしてハッシュにしてkeysに渡します。

keys

「リストコンテキストで呼び出されると、指定したハッシュのすべてのキー、あるいは Perl 5.12 以降でのみ、配列のインデックスからなるリストを返します。」
「ハッシュ要素は見かけ上、ランダムな順序で返されます。 実際のランダムな順序はハッシュに固有です; 二つのハッシュに全く同じ一連の 操作を行っても、ハッシュによって異なった順序になります。」
Perlの組み込み関数 keys の翻訳 - perldoc.jp

say

引数を省略しているので$_を表示します。 この時の$_は外側のforループで1周毎に設定されるkeysが返したリストの要素(ハッシュのキー1個)のエイリアスです。

$world->{$_}

$worldがハッシュのリファレンス、$world->{~}はハッシュのキーが~の場合にペアとなっている値です。 このサンプルでは配列のリファレンスが入っています。

@{$world->{$_}}

配列のリファレンスを配列にデリファレンスします。 配列の要素はハッシュのリファレンスですからfor修飾子で1周毎の$_に入ります(本当はエイリアスです)。 外側のforループ内はハッシュのキーが設定されていましたがfor修飾子が付いた単純文の$_はハッシュのリファレンスです。

$_->{name}

$_はfor修飾子で設定されたハッシュのリファレンスです。 そのハッシュのキーが「name」とペアになっている値(例えば「たこルカ1号」)です。

公式ドキュメント

こっち読んだほうがいいと思う(身も蓋もない)。
perldsc - Perl のデータ構造クックブック - perldoc.jp