おはようございます、しなもんです。
Pythonの公式ドキュメントを適当に見ていたら、めちゃくちゃ面白いコードがあったので紹介したいと思います。
本題
from functools import reduce
# Primes < 1000
print(list(filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0,
map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))))
# First 10 Fibonacci numbers
print(list(map(lambda x,f=lambda x,f:(f(x-1,f)+f(x-2,f)) if x>1 else 1:
f(x,f), range(10))))
# Mandelbrot set
print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+'\n'+y,map(lambda y,
Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM,
Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,
i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y
>=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(
64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy
))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24))
# \___ ___/ \___ ___/ | | |__ lines on screen
# V V | |______ columns on screen
# | | |__________ maximum of "iterations"
# | |_________________ range on y axis
# |____________________________ range on x axis
よい子はまねしないでね!
やばい。
とても公式のドキュメントに書いて良いものではない。
いや、こんなことはしてならないという戒めとしてわざわざ書いてあるのだが。
Pythonコミュニティが本気を出して生み出した
クソコードとなるべくして生まれたクソコードである。
コードゴルフ的には大正解なのかもしれない。(コードゴルフは良く知らない)
Qiitaのコードゴルフ
タグは、2024年7月1日現在83記事である。
とはいえ業務で使ったら間違いなく磔にされるであろう謎テクニックが多数紹介されているので、
興味本位で覗いてみるのも良い経験かもしれない。
せっかくだから解読してみた。
コードがありがたいことに3種類あるのでそれぞれみていく。
2から999までの素数のリストを生成する1行クソコード
print(list(filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0,
map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))))
見やすいように改行してごまかしているが、これは一行のコードである。
一行のコードはこっち
print(list(filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0,map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))))
range(2, 1000)
2から999までの整数のリストを生成。
map(lambda y: ...)
各整数 y についての処理を定義。
reduce(lambda x, y: x * y != 0, map(lambda x, y=y: y % x, range(2, int(pow(y, 0.5) + 1))), 1)
ここで、y
が素数かどうかをチェック。
具体的には、2からy
の平方根までのリストをつくり、その整数でy
を割っていくことで
素数の場合は0
、素数ではない場合は1
を返すようになっている。
y * ...
上の処理で出した数値をyに掛けることで、
y
が素数であればy
、素数でなければ0
を返す。
filter(None, ...)
None
でない値(すなわち素数)だけをフィルタリング。
list(...)
最終的に出された値をリストに変換。
やっていることは分かるが、一つ目のコードから既に度し難すぎる。おかしい。
フィボナッチ数を10個生成
print(list(map(lambda x, f=lambda x, f: (f(x - 1, f) + f(x - 2, f)) if x > 1 else 1:
f(x, f), range(10))))
一行のコードはこっち
print(list(map(lambda x, f=lambda x, f: (f(x - 1, f) + f(x - 2, f)) if x > 1 else 1:f(x, f), range(10))))
こちらも内容自体は難しくないが、ラムダ式の乱用すぎる。
range(10)
0から9までの整数のリストを生成。
map(lambda x, f=lambda x, f: (f(x - 1, f) + f(x - 2, f)) if x > 1 else 1: f(x, f), ...)
各整数x
についてフィボナッチ数を計算。
具体的には、再帰的なフィボナッチ関数を定義し、
そのあとに再帰的な関数f
を呼び出して、x
番目のフィボナッチ数を計算。
list(...)
最終的に出された値をリストに変換。
最初のコードと比べたら短くてマシとか思ってはいけない。
マンデンブロ集合の描画
一番やばいやつである。大本命。
print((lambda Ru, Ro, Iu, Io, IM, Sx, Sy: reduce(lambda x, y: x + '\n' + y, map(lambda y,
Iu=Iu, Io=Io, Ru=Ru, Ro=Ro, Sy=Sy, L=lambda yc, Iu=Iu, Io=Io, Ru=Ru, Ro=Ro, i=IM,
Sx=Sx, Sy=Sy: reduce(lambda x, y: x + y, map(lambda x, xc=Ru, yc=yc, Ru=Ru, Ro=Ro,
i=i, Sx=Sx, F=lambda xc, yc, x, y, k, f=lambda xc, yc, x, y, k, f: (k <= 0) or (x * x + y * y
>= 4.0) or 1 + f(xc, yc, x * x - y * y + xc, 2.0 * x * y + yc, k - 1, f): f(xc, yc, x, y, k, f): chr(
64 + F(Ru + x * (Ro - Ru) / Sx, yc, 0, 0, i)), range(Sx))): L(Iu + y * (Io - Iu) / Sy), range(Sy
))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24))
一行のコードはこっち
print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+'\n'+y,map(lambda y,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM,Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y>=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24))
ちなみにマンデンブロ集合というのは、みんなだいすきフラクタル図形の一種である。
私はこういう高度すぎる数学が一切分からない(記事作成当時高校2年)ので詳細は全く分からない。
とにかく、無限にズームできるおもしれ~図形である。奇妙で綺麗。
気になる人はWikipediaを見に行ってほしい。
https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%B3%E3%83%87%E3%83%AB%E3%83%96%E3%83%AD%E9%9B%86%E5%90%88
パラメータの定義
Ru, Ro: 実部の範囲
Iu, Io: 虚部の範囲
IM: 最大の反復回数
Sx, Sy: 画像の横と縦の解像度
初見では分からんすぎる。さすがにこのコードの解読だけはAIに頼った。
reduce(lambda x, y: x + '\n' + y, map(lambda y, ...))
各行のピクセルを計算し、それを結合して描画。
map(lambda y, ...)
各y
座標に対してピクセルを計算。
reduce(lambda x, y: x + y, map(lambda x, ...))
各x
座標に対してピクセルを計算し、それを結合して行を生成。
map(lambda x, ...)
各ピクセルに対してマンデルブロ集合の判定。
lambda xc, yc, x, y, k, f
マンデルブロ集合の判定を行う再帰的な関数。
よく分からない。
lambda Ru, Ro, Iu, Io, IM, Sx, Sy
マンデルブロ集合のパラメータを受け取り、集合を描画。
終始なにも分からなかった。
一応実行してみた
わざわざVScodeを開いて実行するのが面倒だったので
Discord上でPythonを実行できるBotを召喚してみた。
この二つは合っていそうである。
あちゃー。
ここまで来たら意地でも実行する。
できた。
調子に乗ってサイズの数値を変えた。
なんかとてもcmdの画面には見えないが、cmdである。
一行でここまでできるポテンシャルがpythonにあるということを証明する点では、
これはもうこれでいいのかもしれない。
まとめ
ドキュメント「良い子はまねしないでね!」
(いいね&ストックお待ちしております!!!)