77
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Pythonゴルフテク(AtCoder)

はじめに

AtCoderで今まで培ってきたPython3の中で短く書くテクニックの紹介となります。
あくまでAtCoder上でのテクニックということになります(他のコンテストサイト等で使えるかは知らない)。
ここに書かれているのは、ただ短くするという目的のみで書かれたコードなので、これを真似するのは非推奨であるということにご注意ください。
思いついたことを書いていくのでとっ散らかってると思います。すいません。

標準入力

Pythonの標準入力と言えばinput()を思い浮かべると思いますが、短く書くときは、input()よりもopen(0)が使われがちです。
openはファイルを開く関数ですが、第一引数に0を指定することで、標準入力から読み込んでくれます。
例えば、

4
1
2
3
4

のような入力が与えられ、最初の行を変数nに、残りの行をリストaに格納したい場合、

n,*a=map(int,open(0))

と書くことができます。また、

5 4
1 2 3 4 5

のような入力が与えられ、最初の行をnとk、2行目をリストaに格納したい場合、

n,k,*a=map(int,open(0).read().split())

と書くことができます。

evalを使うことが有効となるケースもあります。
evalは引数で与えられた文字列を式として実行してくれます。なので入力の文字列を適切に加工してevalに渡すことで、短くなることがあります。
例えば、

10 20

のように1行に2つの数値が与えられ、その積を出力せよという問題の場合、

print(eval(input().replace(' ','*')))

と書くことができます。この場合、
入力の文字列の' 'を'*'に置換することで、

10*20

という文字列になり、これを式として実行することで解が得られるということになります。

さらに、置換したい文字列(今回は' 'を'*'にしたい)の長さが共に1のとき、可変長引数を使って、

print(eval(input().replace(*' *')))

と書くことができます。

また、制約で2つの数値が100未満である場合、

s=input()
print(int(s[:2])*int(s[2:]))

と書くこともできます。

出力

あるリストaの中身を空白区切りで出力したい場合、

print(*a)

と書くことができます。
これを改行区切りにしたい場合、

print(*a,sep='\n')

とすれば良いです。
AtCoderでは、解を改行区切りで出力せよという場合でも、空白区切りで出力して通ることが良くあります。

YNeos

Pythonゴルフと聞いてこれを思い浮かべた人は多いと思います。
ある条件を満たすとき'Yes'を、そうでないとき'No'を出力せよというような問題で、

print('YNeos'[条件式::2])

などと書くことができます。
なお、条件式がTrueになるときに'No'を出力するので、無理に条件をひっくり返して長くなるくらいなら、

print('NYoe s'[条件式::2])

のようにしても良いです。
この場合、条件式がFalseになるとき'No '(末尾に空白)が出力されるのですが、AtCoderはこのような場合でも通ることが多いです。

セミコロン

Pythonでは改行以外にセミコロンも文の区切りに使えます。
例えばfor文で複数の処理を書くとき、

for _ in'_'*n:hoge;fuga;piyo

などと書くことができます。
また、このような同じ処理をn回繰り返すようなものの場合、execという引数で与えられた文字列を文として実行してくれる関数を使って、

exec('hoge;fuga;piyo;'*n)

と書くことができます。

boolの演算

boolはintのサブクラスなのでintに対して演算を行えます。
例えば、ある条件を満たしたときaに、満たしてないときにbに1を加算したい場合、

f=条件式
a+=f
b+=1-f

などと書くことができます。

リストへのappend

あるリストaに対して、末尾に0を追加したいとき、

a+=[0]

のように大きさ1のリストを足せば良く、さらに、

a+=0,

ようにタプルを足すこともできます。
ある条件を満たしたときのみ追加したい場合は

a+=[0]*条件式

のように書くことができます。

代入式(セイウチ演算子)

AtCoderの言語アップデートで、Pythonのバージョンが3.8.2となり、セイウチ演算子が使えるようになりました。
自分はまだあまり有効に使えていないのですが、例えば、0で初期化された変数が欲しいとき、open(0)と組み合わせて、

open(x:=0)

とすることができます。

listへの変換

iterableをlistに変換したいとき、

list(iterable)

の代わりに、

[*iterable]

と書くことができます。
同様に、iterableをsetに変換したい場合、

{*iterable}

と書くことができます。

import

例えば

from numpy import*

のように書くことでNumPyの関数がnp.など付けずに使えるようになります。

色々な演算

nをmで割る(切り上げ)

0--n//m

(n+1)*2

n+1<<1

もしくは

-~n*2

(n-1)*2

~-n*2

その他

ABC-Aの自分の提出で面白そうなものをいくつかリンクで貼っておきます。

https://atcoder.jp/contests/abc092/submissions/14703721
f-stringsで

+min(int(input()),int(input()),)+min(int(input()),int(input()),)

という文字列を作り、evalで式として実行します。

https://atcoder.jp/contests/abc115/submissions/4390864
inputは引数を出力できます。

https://atcoder.jp/contests/abc122/submissions/4701952
https://atcoder.jp/contests/abc119/submissions/4376176

おわりに

なにか思いついたら追記していきます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
77
Help us understand the problem. What are the problem?