自分のための練習問題をつくろう

Perlのハッシュや配列、そしてそれぞれのリファレンスを使って、データ構造を作る練習をしたいっていうときに、そのための例題というか練習問題みたいなものを作ってみる、というのは良い方法だと感じる。

たとえば配列なら、果物とか色とかを使うと作りやすい。

#!/usr/bin/env perl
use strict;
use warnings;
use 5.014;

my @fruits = qw(apple orange grape melon lemon strawberry banana);
my $colors = [qw(red blue black green purple pink yellow)];

say $fruits[3]; #=> melon
say $colors->[5]; #=> pink

とか何とか。

これがハッシュ系だと何だろうなあ、と思って、まあそれぞれの役割があるロックバンドとか、スポーツチームとか作りやすいのかな、と思う。

たとえばサッカーなら、エスパルスのMFは誰で、とかアルゼンチン代表のDFは誰で・・とか。サッカーの場合はレギュラー選手だけでも、同じポジションに複数の選手がいたりするから、ハッシュと配列の組み合わせなんか作るのに便利そうだ。

あるいはバンドなんかでも同じようなことは言える。ギターが二人いるバンドも少なくないし、スカパラみたいな大所帯バンドやクラシックのオーケストラまで対象を広げたらかなり大変なことになりそうだ。(いい意味で)

と言いつつ、ぼくはスポーツを熱心には見ないし、オーケストラの実情も知らなければ最近の音楽も知らないから、すぐに浮かぶ例題にできそうな人たちと言ったらとりあえずビートルズぐらいしかいない。

use DDP;

my $beatles = {
    guitar => [qw(John George)],
    bass => 'Paul',
    drums => 'Ringo',
};
p $beatles;

実行すると・・

\ {
    bass     "Paul",
    drums    "Ringo",
    guitar   [
        [0] "John",
        [1] "George"
    ]
}

ギターの二人をさらにハッシュで強引に表現すると、こんなか?

my $beatles = {
    guitar => {
        vocal => 'John',
        leadguitar => 'Gerorge',
    },
    bass => 'Paul',
    drums => 'Ringo',
};

ダンプ(Dump。内部構造をレントゲン的に出力)すると・・

\ {
    bass     "Paul",
    drums    "Ringo",
    guitar   {
        leadguitar   "Gerorge",
        vocal        "John"
    }
}

ふむ。まあ、ジョージも歌いますけどね・・とりあえず便宜的に。

というかビートルズだけでもいくらでも楽しいデータ構造はできそうだ。
たとえば、ジョージがシタールも弾くことをどう表現するか? トカ。
あるいは何年に出たアルバムの何曲目がどんな曲で、それをどう取り出すか? トカ。
夢は広がる。

上記からもう少し進めて、最後に挙げたデータ構造からジョージの名前を取り出すにはどうしたらいいか。
ポクポクポク・・(古い)

say "His name is $beatles->{guitar}{leadguitar}.";

実行。

His name is Gerorge.

オーケー。では同じデータ構造から、リンゴの担当楽器を取り出すにはどうしたらいいか?
当然僕はその楽器を知っているが、便宜的に知らないことにして・・知らなかったらどう取り出すかというゲームです。
ポクポクポク・・(古い)

for (keys %$beatles) {
  if ($beatles->{$_} eq 'Ringo') { 
    say "He plays $_.";
  }
}

実行。

He plays drums.

なんかもっと全然スマートに書けそうですが・・というかプログラム以前に英語がすごいですが。

じゃ、ジョンの担当はなんでしょうか。
熟考・・たぶん上のをチャチャッと書き直せば良さそうだが。

for (keys %{$beatles->{guitar}}) {
  if ($beatles->{guitar}{$_} eq 'John') { 
    say "His role is $_.";
  }
}

実行。

His role is vocal.

ふむ。これもまあ英語の方が問題に思えますが、ヨシとしましょう。

じゃあじゃあ(ムキになって)、上記はハッシュリファレンス使ったけど、普通のハッシュで書き直したらどうなるか。
中身を書き換えるのは面倒なので、大元のビートルズだけ普通のハッシュにしましょう。

こんなですか。

my %beatles = (
    guitar => {
        vocal => 'John',
        leadguitar => 'Gerorge',
    },
    bass => 'Paul',
    drums => 'Ringo',
);

ここから同じようにジョンの担当を出しましょう。

for (keys $beatles{guitar}) {
    if ($beatles{guitar}{$_} eq 'John') {
      say "His role is $_, again.";
    }
}
#=> His role is vocal, again.

ふむ。さっきのはコレなので・・

#再掲
for (keys %{$beatles->{guitar}}) {
  if ($beatles->{guitar}{$_} eq 'John') { 
    say "His role is $_.";
  }
}

ほっとんど変わらないですね。
だから思うんですけど、ことデータ構造について考える場合、リファレンスってたんに「てっとりばやくそれ(ハッシュや配列)を書ける」というだけのものだと考えていいんじゃないか、少なくとも初心者の場合、という気が今はしています。

リファレンスにはもう一個大きな特徴で、そうした多重構造をもったデータをスカラーとして持ち運べる&運んだ先での変更が元に影響をあたえる、とかあると思うんですが、やっぱりそれは当面分けて考えてもいいんじゃ・・とかってことをあらためてこのビートルズの皆さんの様子を見ながら思ったりもしました。

こんな風に、自分で自分に問題を作って、それを解いたりちょっとアレンジとかしたりするの、普通に面白いし、たしかに仕事みたいにヒリヒリしていないから、目が覚めるような突然の向上とかはないかもしれないけれど、何もやらないよりは成長の助けになっていると思うし、単純に楽しい。それが趣味プログラミングの良さで、こんな風にして日々の仕事でダメージを受けたりささくれだったりした何かをなめしている、という気もします。