2015年10月8日木曜日

Pythonのリスト内包表記その2

リスト内包表記を知らなかった私が、前回(http://blackstraycatreboot.blogspot.jp/2015/10/python.html)リスト内包表記はリストの条件付き再リスト化と覚えたばかりだが他にも直接文字列を列挙したりできるらしい。

つい最近
【漫画版: 女子高生プログラマーの大バトル!〜コボール文明の逆襲〜|paizaオンラインハッカソン6】>【遺跡発掘ゲームで古代コボール王Ⅳ世を撃破せよ!|緑川つばめ】
(https://paiza.jp/poh/joshibato/tsubame)の簡単な問題にて

入力値+その値左側(10の位)+その入力の右側(1の位)を足して終わりという簡単な問題
初回は単純に


n=raw_input()
print int(n[:1])+int(n[1:])+int(n)


一度変数に格納してスライスで分解し、intへ変換しつつprint出力しました。
しかし、面白味が無かったので入力値を直接回答叩き込みたくなった。

ところが変数は分解しなければならず、入力値に直接スライスでは値をそのまま返せない。
変数のコピーさえあれいいのに・・・

そこで指定値for系で学んだリストの生成方法を思い出した
ループさせる場合【 for x in range(N) 】みたいな生成が一般的だが【 for x in[0]*N 】の方が生成が早くさらに【 for x in[None]*N 】の方が速い。
今回速度はさて置き、リストは【 [指定値]*数値 】でリストを生成すれば元値を複製できる。


[raw_input()]*3


これで入力値を3つに複製できた。
ですが値を切り出し、さらに数値にして合算する必要がある。

そしてついに話戻ってリスト内包表記!これならリストを列挙しつつしかも最終的な値を直接返せる!
リストに対するint変換は入力値周りで覚えたmapによりintに変換できるし、さらにそれに対して他の問題でやったリスト合算sumが使える。

なるほどこれは簡単に見えて総合問題なんだな(絶対違う)という事に。
だがしかし、ここで少し手が止まる。


print [x for x in[raw_input()]*3]


三回入力値を得られたが処理に変化を加える為の方法がない。
ここで1・2分くらい悩んでenumerateを思い出した。
リスト要素に対し値と要素番号を得られる。これでどうにかしよう。


print [b[::] for i,b in enumerate[raw_input()]*3]

スライスで切り抜くには【 変数[開始インデックス:終了インデックス:ステップ] 】となる。
だがここでまた思案。

iに入ってくるのは0・1・2これを要所に設定した場合格納値は(入力が27の場合)

b[i::]→["27","7",""]
b[:i:]→["","2","27"]
b[::i]→エラー(ステップに0は指定できない

んー惜しい・・・。

開始+0、終了+1なら(入力が27の場合)

b[i:i+1:]→["2","7",""]

んーこれでは全体が入らない。
同時に平行で移動する関係上範囲が一定なのは仕方がない

今が
b[0:1] #2
b[1:2] #7
b[2:3] #""


なので
b[0:1] #2
b[1:2] #7
b[0:2] #27
とかになってくれれば・・・ん?

これ、オーバー通る?
b[0:3] #27
通る

0・1の交互なんて連番なら簡単じゃないか数値の÷2のあまりでいい
じゃあ・・・

b[i%2:i+1:]→["2","7","27"]

キター。
それじゃあ、これにmapかけて

print map(int,[b[(i%2):(i+1)] for i,b in enumerate([raw_input()]*3)])
>>>[2,7,27]

sumで合算してやれば

print sum(map(int,[b[(i%2):(i+1)] for i,b in enumerate([raw_input()]*3)]))
>>>36

できたーーー!時間にして10分なんて難しい総合問題なんだ・・・。




今回の落ち(と、言うか今回はこれの為)
別な問題をやっている時にヒントとかいうのに気付いた

print ''.join([v for k,v in enumerate(raw_input()) if k%2 == 0])

なんか近いのを見たなぁこの黒魔術な感じ、と言うかさっきこの絶対やる必要のない遠まわりな感じの回答したよ。



さておき、今回の落ちが本編なのだが頭に書いた通り、直接文字列を列挙できる。
リスト内包は「リストを再リスト化」しかできないという理解だったが文字列を要素として一文字ずつ取り出すことができる。
上の式では一文字ずつ取り出し、カウンタを2で割ってあまりが0か1かで格納する値を決めて最後に空文字でリストを結合している。

というわけで、リスト内包はリストも文字列もリスト化できるという事でした。
これを書くのに長い毎ふりだったぜ・・・。




蛇足:
ただ、まぁもしもこういう感じにするならわざわざ0を判定するのはあれなので

print ''.join([v for k,v in enumerate(raw_input()) if not k%2])

こうでしょ?・・・いやまあこう言うのが可読性を落とす原因なんだけどね。
(値の返りが何と一致しているから処理されるという明示がなくなる為)
いやでもそもそもこの問題リスト内包してる時点で可読性激落ちですからね。

じゃあどうするのって話だがPythonですからそこは

print raw_input()[::2]

これだけでいいんですよ。

0 件のコメント:

コメントを投稿