うちのTLに流れてきたツイート
puts %w[思考 言葉 行動 習慣 性格 運命].each_cons(2).map { |a, b| "#{a}に気をつけなさい。それはいつか#{b}になるから。" }
— Jun OHWADA at 🏠 (@june29) 2020年9月7日
これはマザーテレサの言葉とされる文字列を表示する ruby のスクリプトです。
ところで、本当にマザー・テレサの言葉かというとどうもそうではないというお話。
さて、このスクリプトを動かすと、こうなります。
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をちょこっと変えて動かしてみます。
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"; }
同じように表示できました。
めでたしめでたし。