LoginSignup
3
1

More than 3 years have passed since last update.

J 言語なら 40 byte で FizzBuzz できる

Last updated at Posted at 2020-08-30

J言語でFizzBuzzを作る という記事でコメントしながら、もっと短く書ける方法を思いついたので紹介します。

FizzBuzz (40 byte)

echo@(, ::]Fizz`Buzz;@#~0=3 5&|)@>:i.100

ちょっと読みにくいですね(J 言語のシンタックスハイライト欲しい)。適宜空白を入れてみましょう。

echo@(, ::] Fizz`Buzz ;@#~ 0 = 3 5&|)@>: i.100

あまり変わらないので 優先順位を考慮して括弧を入れます。

((echo @ ((, :: ]) ((Fizz ` Buzz) ((; @ #) ~) (0 = (3 5 & |))))) @ >:) (i. 100)

余計に読みにくくなってしまいました。とりあえず分解して解説します。

fizzbuzz=. , ::] (Fizz`Buzz ;@#~ 0 = 3 5&|)
echo@fizzbuzz@>: i.100

解説

echo@fizzbuzz@>: i.100

i.100
0 から 99 までの整数のリストです。

echo@fizzbuzz@>:
それぞれの整数を、インクリメント→変換→出力 します。@を使っているのは途中で結果が集められるのを防ぐためです。


fizzbuzz=. , ::] (Fizz`Buzz ;@#~ 0 = 3 5&|)

3 5&|
引数を (3 で割った余り , 5 で割った余り) のリストを作ります。& は、引数を部分適用します。

0 = 3 5&|
(3 で割り切れるか , 5 で割り切れるか) のリストを返すフォークです。

Fizz`Buzz
('Fizz' ; 'Buzz') と同じで、ボックスのリストです。文字数削減のために `悪用使用しています。

;@#~
~ は、右辺と左辺を入れ替える役割をしています。
(0 = 3 5&|) ;@# ('Fizz' ; 'Buzz')"_ と同じ結果になります。
# は、リストをフィルターするのに使っています。
3 で割り切れるときは <'Fizz' が、5 で割り切れるときは <'Buzz' が残ります。
最後に ; でボックスを開いて連結します。結果は 'Fizz' , 'Buzz' , 'FizzBuzz' , 空文字列 のいずれかになります。

, ::]
:: は、conjunction (接続詞)の一種で、, がエラーになれば代わりに ] が実行されます。

, ::] (Fizz`Buzz ;@#~ 0 = 3 5&|)
これはフックで、, ::] の引数は、左辺が元の整数、右辺が上で計算した文字列になります。
文字列が空の場合、, は正常に左辺の整数を要素に持つリストを返します。
そうでない場合、domain error が発生して、代わりに ] が右辺の文字列を返します。
この結果が最終的に echo に渡されます。


コードで表現すると ↓ のようになります(この方が分かりやすいかもしれません)。

isDevisibleBy3_5=. 0 = 3 5&|

boxedFizzBuzz=. Fizz`Buzz

filterAndJoin=. ;@#

replaceEmpty=. , ::]

fizzbuzz=. replaceEmpty (boxedFizzBuzz filterAndJoin~ isDevisibleBy3_5)

echo@fizzbuzz@>: i.100

参考

NuVoc
↑ とりあえず分からないときはこれで調べるといいと思います。
プリミティブの一覧の他に Ancillary Pages が結構役に立ちます。


日本語の情報が少ない or 古いので、いつか J 言語の布教入門記事を書きたいと思います(実行するかどうかは別)。

3
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1