Pythonでナベアツしてみた

はじめに

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/4else側に埋め込みます。

>>> 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行でかなりのことができることがお分りいただけたかと思います。
正直、僕もできると思って挑戦していなかったので、驚きました。

はじめ、シーケンスの概念や扱い方について、事細かに書いてあったのですが、
書き進めていくうちに読みにくくなり、前半と後半でかなりレベルが違ったので、
初心者向けの内容はカットしました。

ワンライナーで何かを書いても解説記事を書くべきではないですね。
おそらくほとんどの人が読まず、コードを追って読もうとするひとには解説は必要ないでしょう。

ワンライナーでナベアツをするよりも、数字を日本語に変換するプログラムの方が   実装に時間がかかりました。