Python コードゴルフテクニック集

# はじめに
[CodinGame](https://www.codingame.com/home)というコードゴルフで競い合えるサイトがあるのですが、そこで学習した文字数を減らすテクについて解説します。
順番が非常に雑です。
## 空白
削れる空白は積極的に削っていきましょう。

```python:old
n = int(input())
print(n * 2)
```

```python:new
n=int(input())
print(n*2)
```

数字と文字の間も削れるところは削れたりします。

```python
print(1if"hoge"==input()else 0)
```

## 変数
1文字の変数はa-z,A-Zの52個あります。変数は基本的に1文字にしましょう。

```python:old
Answer=0
for i in range(5):Answer+=int(input())
print(Answer)
```

```python:new
A=0
for i in range(5):A+=int(input())
print(A)
```

## 演算子

演算子には優先順位がありますが、優先順位が同じ演算子は基本的に左から計算します。

```python:old
N=int(input())
print(3*(N//3))
```

```python:new
N=int(input())
print(N//3*3)
```

このようにして括弧を減らしていきましょう。

##入力
###変数に渡さない
入力値が必要ない場合は、単に `input()` として無視しましょう。
一回だけ入力値を必要とする場合は、式の中に `input()` を入れ込むと変数の長さ分削減できます。

```python:example
#1行目に文字列の長さが渡されて、2行目の文字列のASCIIコードの値の合計を計算
input()
print(sum(ord(i)for i in input()))
```

##出力
###リストのアンパック
`*`演算子は、リスト内の値を全て出力するときに便利です。
オプション`sep`の値で区切ります。

```python:example
print(*map(len,input().split()),sep="a")
#入力例 think sinking thonking
#[5,7,8]となるので
#出力例 5a7a8
```

###改行無し
改行したくない場合は、`print()`関数のオプションである`end`を使いましょう。

```python:example
print(end="hoge")
```

##f文字列（フォーマット済み文字列リテラル）
**f文字列は大変便利です。**ここではコードゴルフで主に用いるものを挙げていきます。
###穴埋め
f文字列の基本です。中括弧`{}`で囲ったところに整数、文字列、変数を埋め込みます。
`{}`のなかに文字列を入れたいときは、シングルクォーテーション`'`とダブルクォーテーション`"`を使い分けましょう。

```python:example
#左の数値が右の数値より大きいかどうか
A,B=map(int,input().split())
print(f"{A} is {'not '*(A<=B)}bigger than {B}")
```

###ゼロ埋め
```python:example
#時刻表示
second = int(input())%86400
print(f"{second//3600:02}:{second%3600//60:02}:{second%60:02}")
```

###進数変換
```python:example
#先程の0埋めとも組み合わせられます
print(f"{int(input()):b}")#2進数
print(f"{int(input()):o}")#8進数
print(f"{int(input()):08x}")#16進数で8桁まで0埋め
```

##整数
###1文字の不等号
`>=` より `>` 、`<=` より `<` を使った方が短いです。

```python:old
if n<=7:print("Yes")
```

```python:new
if n<8:print("Yes")
```
###+1,-1
`n+1` は `-~n` 、`n-1` は `~-n` と表せます。
文字数変わらないのに何が嬉しいんだよというと、`-` と `~` は `*/%` より優先順位が高いので括弧をつける必要がなくなります。

```python:old
print((n+1)%3)
```

```python:new
print(-~n%3)
```
###切り上げ
`n/m` を切り上げた整数は、`math.ceil(n/m)` と書くよりも `(n+m-1)//m` とした方が短く、さらにmathモジュールをimportする必要がなくなります。

```python:old
import math
print(math.ceil(n/m))
```

```python:new
print((n+m-1)//m)
```

###bool値も整数
`True` は `1` 、`False` は `0` にあたります。

```python:example
A=[9,9,8,2,4,4,3,5,3]
print(sum(i>=5for i in A))#4
```

##文字列
###YNeos


```python:example
print("YNeos"[0か1::2])
```

で短くできます。これは　

```python:other
print(["Yes","No"][0か1])
```

よりも短いです
さらに、この手法が本領発揮するのは3つ以上を場合分けする時です。
例えば、 `n`を3で割った余りで `think,thonk,sink` を出力仕分けたいときは、

```python:old
print(["think","thonk","sink"][n%3])
```

とするよりも、

```python:new
print("ttshhiionnnkkk"[n%3::3])
```

とするとかなりの文字数削減です。この場合は、

```python:newofnew
print("ttshhiio"[n%3::3]+"nk")
```

とすれば更に短くできます。

似たようなテクで、bool値の足し算を利用した場合分けもあります。

* $N \leq 5$ のとき、"small"
* $5 \lt N \leq 30$ のとき、"medium"
* $30 \lt N$ のとき、"large"

と場合分けしたい時は、

```py
["small","medium","large"]
```

という配列を作り、indexで場合分けするコードを書きましょう。

```py:example
N=18
print(["small","medium","large"][(N>5)+(N>30)])
```

##変数に関数を代入
1文字変数に何回も使う関数を代入することで短くかけたりします。

```python:code
R = range
N,M,L = map(int,input().split())
for i in R(N):pass
for i in R(M):pass
for i in R(L):pass
```

変数には組み込み関数だけでなくメンバ関数も代入できます。

```python:code
C = [3,1,4,1,5,9,2,6,5,3,5,9].count
print(C(3))#2
print(C(5))#3
print(C(7))#0
```

##ループ

###ループの最後
ループの最後は、下にインデントを開けて書かずに横にかけます。
一行に文を複数書くときは、セミコロンを用います。
また、2重以上のループでもインデントは空白1個分にしましょう。

```python:code
#while文やif文でも同じです
for i in range(N):
 if hoge:print("Yes");break
```

###execによるループ

```python:old
for _ in range(N):処理
```

上のようにループカウンタを用いない場合は、`exec()`関数を用いて短くかけます。

```python:new
exec("処理;"*N)
```

例えば $N=5$の場合は、次のコードと同じ意味です。

```python
処理;処理;処理;処理;処理;
```

###重数を減らす

```python:old
for i in range(N):
 for j in range(M):pass
```

この二重ループを一重ループにするテクです

```python:new
for k in range(N*M):i,j=k//M,k%M;pass
```

##open(0)
挙動が少し難しいですがこれを使いこなせると時に数十bytesの削減になります。
まずは単純に

```python:code
A = open(0)
print(A)
```


こうすると、標準入力にかかわらず出力は、

```:output
<_io.TextIOWrapper name=0 mode='r' encoding='UTF-8'>
```

と出てきて、は？となります。
ところが左辺(`A`)のところを2変数にすると挙動が変わってきます。

```python:code
A,B = open(0)
print(A)
print(B)
```

そして標準入力を

```:input
attack
guard
```

とします。
標準出力は次のようになります。

```:output
attack

guard
```

これは、変数Aには `"attack\n"`, Bには `"guard"` が格納されていたことを表します。

左辺が2変数以上だと、`左辺=open(0)`は次のような処理をします。

1. 標準入力を全て読み込む (今回は `"attack\nguard"` )
1. \nで区切ってリストにする。この時末尾の改行は残る。  
   ( `"attack\nguard"` → `["attack\n","guard"]` )
1. 各変数に順番に代入する (`A = "attack\n", B = "guard"`)

ここで、アスタリスクを用いたアンパック代入を用いることで、
> $1$行目に $N$ が与えられ、$2$ ~ $N$+$1$行目に整数が一つづつ与えられる

という超典型標準入力を、

```python:code
N,*L = map(int,open(0))
```

で簡単に書き表すことができます。

しかし、次のような入力形式だと困ってしまいます。

> $1$行目に $N$ が与えられ、$2$行目に$N$個の整数が空白区切りで与えられる

`open(0)` は改行で区切るので同じようには上手くいきません。
それでも、`open(0).read().split()`が使えます。
`open(0).read()`で標準入力全てを**str型**として受け取れるので、`split()`で空白and改行区切りできます。

```python:code
N,*L = map(int,open(0).read().split())
```

##数式変形
いきなり例題。
> $N^0,N^1,\cdots N^M$ の総和を出力せよ。

単純に書くと次のようになります。

```python:old
N,M=map(int,input().split())
print(sum(N**i for i in range(M)))
```

しかし、このような単純な総和を簡潔に表せないのは**直感的に嫌な気分になります**。
そこで、この数式を†Wolfram Alpha†に突っ込みます。
![スクリーンショット 2021-06-08 21.20.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609652/77ce7f63-04db-bf06-d152-e375a6545456.png)

ということで、

```python:new
N,M=map(int,input().split())
print(~-N**M//~-N)
```

#おわりに
量が少なすぎる　気が向いたら追加