「俺の許嫁と幼なじみが修羅場すぎる」で学ぶワンライナー


背景

python歴数年だけど、普段はlambdaやreduceやmap関数なんてあまり使わない。
せっかくなのでpaizaでいまやってる『俺の許嫁と幼なじみが修羅場すぎる』を
pythonのワンライナー縛りで解いていって勉強してみよう!

ワンライナーとは

複数行をまとめて1行で書ききること。書いていると楽しくなる ʅ(◔౪◔ ) ʃ

# 偶数の合計を出力
r = 0
for x in xrange(100):
  if x % 2 == 0:
    r += x
print r
> 2450

# ワンライナーで偶数の合計を出力
print sum([x for x in xrange(100) if x % 2 == 0])
> 2450

1問目

問題文はこれ

文字列から奇数の文字だけ抜き出してprintすればいいみたい

# まずは普通に解いてみる
input_lines = raw_input()
result = ''
count = 1
for s in input_lines:
    if count % 2 == 1:
        result += s
    count +=1
print result

OneLineにするために使えそうな関数を調査してみる

# 変数のrを利用しない方法だと、1文字ずつのListにして連結すればよさそうだ
print ''.join(['o', 'h', 'a', 'y', 'o'])
> ohayo

# 変数count邪魔すぎい...
# djangoのforloop counterみたいに自動でカウントできる関数ないか調べてみたら
# enumerateを使うと良いみたいだ。
for idx, x in enumerate(xrange(100, 103)):
  print idx, x
>0 100
>1 101
>2 102

# 以上の関数を使って変数2つを消す
l = []
for idx, x in enumerate(raw_input()):
  if idx % 2 == 0:
    l.append(x)
print ''.join([str(_l) for _l in l])

# for文をOneLineにする
l = []
[l.append(x) for idx, x in enumerate(raw_input()) if idx % 2 == 0]
print ''.join([str(_l) for _l in l])

# lを使わないように書き換えると完成!
print ''.join([s for i, s in enumerate(raw_input()) if i % 2 == 0])


無事テストケース通過

可読性がめっちゃ悪い。メンテしたくないプログラムが完成

2問目

問題文はこれ

改行区切りのtextを週毎にサマリーすればいいみたい

# まずは普通に解いてみる
from collections import defaultdict
d = defaultdict(int)
for i in xrange(int(raw_input())):
    d[i % 7] += int(raw_input()) 
for key in d:
    print d[key]

そして詰む

1時間考えても方法が出てこない。。。俺のOneLine力はこの程度なのか。。。
raw_input()で取得できる値が1行目がファイル全体の行数で
2行目以降がサマリーすべき値なのでどう扱えばいいか悩む

# default dictなしに書き換える
l = [0 for x in xrange(7)]
for i in xrange(int(raw_input())):
    l[i % 7] += int(raw_input()) 
print '\n'.join([str(x) for x in l])


# lambda式使うために、リストの初期化を廃止してif,elseで書いてみる
from collections import defaultdict
l= []
for i in xrange(int(raw_input())):
  if i >= 7:
    l[i % 7] += int(raw_input())
  else:
    l.append(int(raw_input()))
print '\n'.join([str(x) for x in l])

# raw_input()部分を分離して考えるために、その部分だけOneLineにする
l = [int(raw_input()) for x in xrange(int(raw_input()))]

# zipとiterで1次元配列を7区切りの2次元配列にする
# 変換前: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
# 変換後: [(1, 2, 3, 4, 5, 6, 7), (8, 9, 10, 11, 12, 13, 14)]
l = [int(raw_input()) for x in xrange(int(raw_input()))]
seven = zip(*[iter(l)]*7)

# zipで行と列を反転する
# 変換前: [(1, 2, 3, 4, 5, 6, 7), (8, 9, 10, 11, 12, 13, 14)]
# 変換後: [(1, 8), (2, 9), (3, 10), (4, 11), (5, 12), (6, 13), (7, 14)]
l = [int(raw_input()) for x in xrange(int(raw_input()))]
seven = zip(*[iter(l)]*7)
r = zip(*seven)
# 出力
print '\n'.join([str(sum(_r)) for _r in r])


# これをとりまとめると。
print '\n'.join([str(sum(_r)) for _r in zip(*zip(*[iter([int(raw_input()) for x in xrange(int(raw_input()))])]*7))])

無事テストケース通過

自身を混乱させるraw_input()部分を、思い切って1行で書ききったところがブレイクスルー。
その後はスルスル解けました。難解な要素を切り離して考えることが大事みたいです。

いままでiter関数なんて一度も使ったことが無かったのですが、こんな使い方するんですね。
Pythonの組み込み関数を初めてちゃんと読みました。