はじめに
FizzBuzz投稿後、アルバイトの仲間に「FizzBuzzのあとは、ナベアツですか?」なんて言われたので、やってみることにしました。
せっかくなので、Pythonのシーケンス操作 の特性をつかって、ワンライナー でやってみましょう。
準備
ナベアツとは
【お笑い】R1「世界のナベアツ・3の倍数」2008年 | YouTube をご覧ください。
当時は、芸人さんでしたが、今は落語家さんになっており、桂三度という名前で活動されています。
今回は、冒頭のネタのように3の倍数または3の付く数字のときは アホ になり、5の倍数のときは、犬っぽい 文字列を出力します。
とりあえずつくりはじめよう
join関数
文字列のリストをセパレーター文字列で結合します。
>>> print " ".join(["a", "b", "c"]) "a b c"
range関数
引数の値までの整数値のリストを返します。
>>> print range(3) [0, 1, 2]
map関数
シーケンスの全ての値に、関数を適応します。
>>> print " ".join(map(lambda i: str(i), range(3))) "0 1 2"
もし5の倍数なら犬っぽくなる
Pythonでn回に一回だけ正を返す・一回だけ負を返すやPythonの条件演算子と遅延評価を見比べるを参考にすると、コードの理解が深まると思います。
a if c else b
の条件演算子の文法で、c
が真だった場合、a
を、偽だった場合、c
を返すことができます。
>>> print " ".join(map(lambda i: u"ワン" if i%5/4 else str(-~i), range(100))) "1 2 3 4 ワン 6 7 ..."
str(-~i)
については、PythonでFizzBuzzしてみた | hacknoteのどこかで書いてあります。
randamモジュールをインポートして鳴き声を変える
Pythonでは、import文が用意されていますが、ワンライナーではimport文はNGです。
そこで、__import__
関数を使います。
lambda
文で無名関数を定義し、即時実行の引数としてモジュールをインポートします。
>>> print (lambda r: " ".join(map(lambda i: r.choice([u"ワン", u"ワーン", u"ワオーン"]) if i%5/4 else str(-~i), range(100))))(__import__("ramdam"))
3の倍数か3のつく数でアホと出力する
3の倍数は、5の倍数と同じようにi%3/2
で判定できます。
3のつく数は、in
演算子でstr(-~i)
の中に、3
があるかどうかを判定します。
(lambda s: u"アホ" if i%3/2 or '3' in s else s)(str(-~i))
をi%5/4
のelse
側に埋め込みます。
>>> print (lambda r: " ".join(map(lambda i: "ワン" if i%5/4 else (lambda s: u"アホ" if (i%3/2 or '3' in s) else s)(str(-~i)), range(100))))(__import__("ramdam"))
3の倍数か3のつく数でアホになる
数字を平仮名にすることで アホさを表現したいと思います。
reduce
関数は、シーケンスをひとつにまとめる時に使います。
下の例では、lambda関数の結果を次の引数として与え、内部的には((10 + 4) + 6)
のような計算がいこなわれています。
>>> reduce(lambda a,b:a +b, [10, 4, 6]) 20
reversed
はシーケンスを逆順にする関数、enumerate
はシーケンスのインデックスと値をタプルで返す関数です。
これらを使うと、桁数の数字と値の文字が取得でき、1桁目は、0のインデックスを持って返ってくるので計算が楽です。
これら使って数値を自然な日本語に変換します。
(lambda s, a:reduce(lambda l,c:(a[c[0]] if c[0]>0 and c[1]=='1' else a[c[1]]+a[c[0]])+l if c[1] in s else a[c[1]]+l,enumerate(reversed(s)),'') if (i%3/2 or '3' in s) else s)(str(-~i),{'1':'いーち','2':'にぃ','3':'さぁん','4':'よん','5':'ごぉ','6':'ろぉく','7':'なぁな','8':'はぁち','9':'きゅう','0':'',0:'',1:'じゅう',2:'ひゃく'})
これを先ほどのアホ
の位置に埋め込んで完成です。
完成品
例によって、結果が寂しくなるのがこわかったので、絵文字を使用しました。
アホの時と、犬っぽくなる時と普通の時の3パターンあります。
まとめ
シーケンス操作を活用するとPythonでも1行でかなりのことができることがお分りいただけたかと思います。
正直、僕もできると思って挑戦していなかったので、驚きました。
はじめ、シーケンスの概念や扱い方について、事細かに書いてあったのですが、
書き進めていくうちに読みにくくなり、前半と後半でかなりレベルが違ったので、
初心者向けの内容はカットしました。
ワンライナーで何かを書いても解説記事を書くべきではないですね。
おそらくほとんどの人が読まず、コードを追って読もうとするひとには解説は必要ないでしょう。
ワンライナーでナベアツをするよりも、数字を日本語に変換するプログラムの方が 実装に時間がかかりました。