このコードが何をやっているのか教えてください。
$_=3x(1E3-1),s/3/++$p%3*$p%5?7:5x$p/ge,print s/5//g
以下のコードと同じで3または5で割り切れる1000までの数を足した結果が得られることは知っていまが、それぞれの記号が何を意味するのか分かりません。
$sum=0;
map {$sum += $_ if(!($_%3) || !($_%5))} 1..1000;
print $sum;
最近 perl を使い始めたので良くわかっていません。
よろしくお願いします。
まず一番の大外だけを見ると以下のようになっており、カンマ演算子が使われています。
A, B, C;
カンマ演算子は、左辺の値を捨てて右辺の値を返す演算子です。上記は、Aを評価して結果を捨てて、Bを評価して結果を捨てて、Cを評価してその値を返していおり、この例では以下のように解釈して構わないと思います。
$_=3x(1E3-1); s/3/++$p%3*$p%5?7:5x$p/ge; print s/5//g;
次に、$_=3x(1E3-1) の説明です。
次に、s/3/++$p%3*$p%5?7:5x$p/ge の説明です。
つまり上記は $_ で 3 を見つける度に ++$p%3*$p%5?7:5x$p というPerlの式を実行することになります。$_ は3が999個並んだ文字列なので ++$p%3*$p%5?7:5x$p が実行されるので以下のように解釈が可能です。
$new = ""; for($i=0, $i<999, $i++) { $new .= ++$p%3*$p%5?7:5x$p; } $_ = $new;
ここで、
これらをふまえると上記は以下のように解釈できます。
$new = ""; for($i=0, $i<999, $i++) { $p = $p + 1; #↓ここでは計算結果の値に余り意味はなく剰余計算を行う際に$pが3の倍数か5の倍数の時にゼロが掛け算されてゼロ(偽値)になります if($p%3*$p%5) { #↓$pが3の倍数か5の倍数のときに実行される $new .= 7; } else { #↓$pが3の倍数でなく、5の倍数でもないときに実行される $new .= 5x$p; #5を$p回繰り返した文字列 } } $_ = $new;
さて、頭のいくつかの3を置換してみましょう
3が置換される値 | コメント | |
---|---|---|
1回目 | 7 | $p=1なので7 |
2回目 | 7 | $p=2なので7 |
3回目 | 555 | $p=3で3の倍数なので5x3で555 |
4回目 | 7 | $p=4なので |
5回目 | 55555 | $p=5で5の倍数なので5x5で55555 |
6回目 | 555555 | $p=6で3の倍数なので5x6で555555 |
7回目 | 7 | $p=7なので |
8回目 | 7 | $p=8なので |
9回目 | 555555555 | $p=9で3の倍数なので5x9で555555555 |
最終的に $_ は 7755575555555555577555555555... という文字列になります。
最後に、print s/5//g を説明します。
さて、ここで上の 3 を 7 や 5x$p に置換したときの表を見てみます。
よく見ると$pが3の倍数の場合は5が$p個、$pが7の倍数の場合も5が$p個出力されており、$pは1から1000までの値をとります。
すなわち $_ に入っている5の数を数えることは、1から1000までの5の倍数と7の倍数の値を数えることと同じ意味になることが分かります。
以上です。
ここまでの説明で疲れたので、後者の $sum=0~ の説明は適当です。
$sum=0;
変数 $sum に 0 を代入。
map {$sum += $_ if(!($_%3) || !($_%5))} 1..1000;
map { } 1..1000 で「1~1000まで、{}の中を繰り返し実行」します。
{}の中では実行されるたび、変数 $_ に1~1000が代入されます。そして
変数($_)が3で割り切れる、または変数($_)が5で割り切れるなら、合計($sum)に
仮変数($_)の値を足していきます。
print $sum;
最後に変数 $sum の値を表示。
すみませんが、私が知りたかったのは上の方のコードです…
まず一番の大外だけを見ると以下のようになっており、カンマ演算子が使われています。
A, B, C;
カンマ演算子は、左辺の値を捨てて右辺の値を返す演算子です。上記は、Aを評価して結果を捨てて、Bを評価して結果を捨てて、Cを評価してその値を返していおり、この例では以下のように解釈して構わないと思います。
$_=3x(1E3-1); s/3/++$p%3*$p%5?7:5x$p/ge; print s/5//g;
次に、$_=3x(1E3-1) の説明です。
次に、s/3/++$p%3*$p%5?7:5x$p/ge の説明です。
つまり上記は $_ で 3 を見つける度に ++$p%3*$p%5?7:5x$p というPerlの式を実行することになります。$_ は3が999個並んだ文字列なので ++$p%3*$p%5?7:5x$p が実行されるので以下のように解釈が可能です。
$new = ""; for($i=0, $i<999, $i++) { $new .= ++$p%3*$p%5?7:5x$p; } $_ = $new;
ここで、
これらをふまえると上記は以下のように解釈できます。
$new = ""; for($i=0, $i<999, $i++) { $p = $p + 1; #↓ここでは計算結果の値に余り意味はなく剰余計算を行う際に$pが3の倍数か5の倍数の時にゼロが掛け算されてゼロ(偽値)になります if($p%3*$p%5) { #↓$pが3の倍数か5の倍数のときに実行される $new .= 7; } else { #↓$pが3の倍数でなく、5の倍数でもないときに実行される $new .= 5x$p; #5を$p回繰り返した文字列 } } $_ = $new;
さて、頭のいくつかの3を置換してみましょう
3が置換される値 | コメント | |
---|---|---|
1回目 | 7 | $p=1なので7 |
2回目 | 7 | $p=2なので7 |
3回目 | 555 | $p=3で3の倍数なので5x3で555 |
4回目 | 7 | $p=4なので |
5回目 | 55555 | $p=5で5の倍数なので5x5で55555 |
6回目 | 555555 | $p=6で3の倍数なので5x6で555555 |
7回目 | 7 | $p=7なので |
8回目 | 7 | $p=8なので |
9回目 | 555555555 | $p=9で3の倍数なので5x9で555555555 |
最終的に $_ は 7755575555555555577555555555... という文字列になります。
最後に、print s/5//g を説明します。
さて、ここで上の 3 を 7 や 5x$p に置換したときの表を見てみます。
よく見ると$pが3の倍数の場合は5が$p個、$pが7の倍数の場合も5が$p個出力されており、$pは1から1000までの値をとります。
すなわち $_ に入っている5の数を数えることは、1から1000までの5の倍数と7の倍数の値を数えることと同じ意味になることが分かります。
以上です。
ここまでの説明で疲れたので、後者の $sum=0~ の説明は適当です。
詳細な回答ありがとうございます。
上のワンライナーのコードが私の質問でして、下のは私が書いたコードでした。
もう少し分かりやすく質問をするべきでした。
単純な演算子の説明までさせてしまってすみません。
三項演算子を展開して if 文で書いてくれているところのコメントが if と else で逆だと思います。
$p%3*$p%5 で論理演算子を使わなくても、「3または5で割りきれない」を表現できるんですね!
置換して、条件を満たす置換した箇所を数えるのが全体の流れだと分かりました。
また、それぞれの式の満たす意味も分かりました。
ありがとうございました。
詳細な回答ありがとうございます。
上のワンライナーのコードが私の質問でして、下のは私が書いたコードでした。
もう少し分かりやすく質問をするべきでした。
単純な演算子の説明までさせてしまってすみません。
三項演算子を展開して if 文で書いてくれているところのコメントが if と else で逆だと思います。
$p%3*$p%5 で論理演算子を使わなくても、「3または5で割りきれない」を表現できるんですね!
置換して、条件を満たす置換した箇所を数えるのが全体の流れだと分かりました。
また、それぞれの式の満たす意味も分かりました。
ありがとうございました。