sironekotoroの日記

Perl で楽をしたい

マザーテレサの(ものとして流布されている)言葉をPerlで

うちのTLに流れてきたツイート

これはマザーテレサの言葉とされる文字列を表示する rubyスクリプトです。

ところで、本当にマザー・テレサの言葉かというとどうもそうではないというお話。

blog.blueeli.jp

さて、このスクリプトを動かすと、こうなります。

20-09-08 15:02:50 ~
$ ruby -e 'puts %w[思考 言葉 行動 習慣 性格 運命].each_cons(2).map { |a, b| "#{a}に気をつけなさい。それはいつか#{b}になるから。" }'
思考に気をつけなさい。それはいつか言葉になるから。
言葉に気をつけなさい。それはいつか行動になるから。
行動に気をつけなさい。それはいつか習慣になるから。
習慣に気をつけなさい。それはいつか性格になるから。
性格に気をつけなさい。それはいつか運命になるから。

左から右へ、メソッドチェーンで書かれていて面白いですね。

each_cons() ?

ruby がわからないうちでも、配列的なところから要素を2つずつ選んで、1つずつずらしながら表示している、というのはわかります。。

こういうの見ると、 Perl ではどう書くんかな〜って思いますよね?

・・・each_cons って関数がまず Perl にないっすね。

Perl each_cons でググります。

そのまんまの名前がついた List::EachCons モジュールを発見。

あるもんだなぁ。

いつも通り cpanm List::EachCons でインストール。そして、SYNOPSYSをちょこっと変えて動かしてみます。

metacpan.org

use List::EachCons;
my @list = qw/思考 言葉 行動 習慣 性格 運命/;
each_cons 2, @list, sub {

    print
        "$_[0]に気をつけなさい。それはいつか$_[1]になるから。\n";

};

うまく動きます。

モジュール使わないと・・・?

さて、モジュール使わない場合はどうなるんでしょう?

Perlでは、配列から複数の要素を取得できるスライスという機能があります。

my @list = qw/思考 言葉 行動 習慣 性格 運命/;

print @list[0,1] . "\n"; # 思考言葉

例では、配列 @list の 0番目と 1番目を print しています。

複数の値が返り値になるので、シジルが @ であることに注意です。

これを使って、2 つずつ配列から取り出してみます。

my @list = qw/思考 言葉 行動 習慣 性格 運命/;

print @list[0,1] . "\n"; # 思考言葉
print @list[1,2] . "\n"; # 言葉行動
print @list[2,3] . "\n"; # 行動習慣
print @list[3,4] . "\n"; # 習慣性格
print @list[4,5] . "\n"; # 性格運命

それっぽくなりましたね。

そして、このスライスのところに規則性が見えますね・・・ [0,1], [1,2], [2,3], [3,4], [4,5]

ここもわざわざ直接入力しなくても良さそうではありませんか?

ってことで、書いてみました。

scalar @list と書くことで、配列 @list の要素数が返ります。

my @list = qw/思考 言葉 行動 習慣 性格 運命/;

for my $index ( 0 .. scalar @list ) {
    last if $index == $#list; # 6番目の要素「運命」にきたら、そのペアとなる次の単語がないのでループを抜ける

    print
        "$list[$index]に気をつけなさい。それはいつか$list[$index+1]になるから。\n";
}

同じように表示できました。

めでたしめでたし。