100までの素数をエラトステネスの篩を使って列挙するプログラムを、Pythonで、defもifもwhileもforも使わずに1行(66文字)で作りました。以下はその作成過程のログです。
__
おおっと、今知りました。(via 竹迫さんの記事)
キミならどう書く 2.0 - ROUND 1 - — Lightweight Language Ring
締め切りまであと30分しかないですね。うわー、もっと早く気づいていれば…。30分でPythonでdefもifも使わずに1行で素数を求めるなんて(勝手に問題を難しくしすぎ)
def foo(x): return [x[0] + [x[1][0]], [y for y in x[1] if y % x[1][0] > 0]]
あと29分!
>>> i = [[],range(2,100)]
>>> while (i[1] != []): i = foo(i)
>>> i
[[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97], []]
とりあえず素数出た!ボーダーラインはギリ越えた!
あと24分!whileを使わずにwhileを作るには…
>>> def foo(x):
if x[1] == []:
return x[0]
else:
return foo([x[0] + [x[1][0]], [y for y in x[1] if y % x[1][0] > 0]])
>>> foo([[],range(2,100)])
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
あと22分!
ifを使わずに分岐をするには…
>>> def foo(x): return (x[1] == []) and x[0] or (foo([x[0] + [x[1][0]], [y for y in x[1] if y % x[1][0] > 0]]))
>>> foo([[],range(2,100)])
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
あと20分。うーん、再起を使ってしまうと関数定義で確実に1行使うので1行にまとめることが出来ない…。とりあえず時間がないから現状でコミットしてから考えるか…。
foo = lambda x:(x[1] == []) and x[0] or (foo([x[0] + [x[1][0]], [y for y in x[1] if y % x[1][0] >
0]]));foo([[],range(2,100)])
関数定義をラムダ構文にして解決。
__
改めてすでに投稿されているものを見てみると…ああ、Pythonでもっと短く作っている人が複数いる…orz。
時間がなくてじっくり既出コメントを読む暇がなかったのですよ、とイイワケ。
4つ目くらいの「圧倒的にPythonに不利な設定ですね!」を見て「そんなわけない!」と奮起したもので。
まぁ、負けてしまったのは仕方がないのでcoolな回答をピックアップしてみるとしますか。
[p for p in range(2,100) if 0 not in [p%d for d in range(2,p)]]
一つ目、なぜこれを思いつかなかったのかちょっと悔しいです。range(2,p)が「2以上p未満の整数」のリストなので[p%d for d in range(2,p)]が「「2以上p未満の整数すべて」でpを割ったあまり」のリストになります。その中に一つでも0があるなら、「2以上p未満の整数の中にpを割り切るものがある」、つまり素数でないということになります。
どれでも割り切れないものだけを残せば残るのは素数っていうわけです。シンプルかつ完璧。
filter(lambda i:reduce(lambda x,y: x*(i%y), range(2,i), 1), range(2, 100))
これも原理は一緒ですね。「2以上i未満の整数」のリストを作って、初期値1であまりを次々とかけていくと、もし0があるなら結果は0になるし、0がないなら結果は0にならない、というわけです。
__
まぁ、初戦は惨敗しましたが、二回戦以降があるならぜひ参加したいところであります。今度トラックバックする時はタイトルにPythonって入れます…。大あわてでトラックバックしたので割と見苦しいですね(´・ω・`)すみません。
__
せめてもの罪滅ぼし(?)に僕が書いたコードの「途中結果を関数への引数として渡す」という設計を見直して72行に縮めてみました。あとPythonインタプリタの直前に評価したものが「_」という名前の変数に入る仕組みを利用して代入も削ってみました。
lambda x:x and([x[0]]+_([y for y in x if y%x[0]]));_(range(2,100))
これでも66文字で、上で取り上げたcoolな解には3文字ほど負けているんですよね…。
自分が負けを認めたくないだけなのだと気がついたので勝ってそうな所で勝負してみよう。所要時間をチェック。
0.00555266102256
0.000577168327259
やった10倍速い。
これで満足して眠れます(笑)