Edited at

Python2で競技プログラミングする時に知っておきたいtips(制御構造編)

More than 1 year has passed since last update.

Python2で競技プログラミングする時に知っておきたいtipsの,制御構造についての部分を分割しました.

Pythonのバージョンは2.7.5(Python3では,入出力などの仕様が大きく異なるので,他の記事を参照することをおすすめします).


条件分岐


条件式に変数を渡す

個人的にはあまり好きではないが,コード量削減のために,

while 1:

a = input()
if not a:
break
# ...

みたいに,if文,while文などの条件に変数を渡すことが多い気がする.

PythonでIf文に変数を入れたときの結果 - LIFE WITH PYTHON


結果

int
0ならFalse,それ以外ならTrue

float
0.0ならFalse,それ以外ならTrue

str
''(空文字)ならFalse,それ以外ならTrue

list
[]ならFalse,それ以外ならTrue

tuple
()ならFalse,それ以外ならTrue

dict
{}ならFalse,それ以外ならTrue

set
set()ならFalse,それ以外ならTrue

None
False


処理を途中で終了したい

入力の終わりを表す記号や,コーナーケースが入力された場合など,途中でスクリプトの実行を終了してしまった方が楽な場合がある.

このような場合は,quit()またはsys.exit()を使うとよい.

a = input()

if a == 0:
quit()
# ...

import sys

a = input()
if a == 0:
sys.exit()
# ...


繰り返し


range()とxrange()

2. 組み込み関数 — Python 2.7ja1 documentation

Pythonで「○○をn回行う」と言った単純な繰り返しを実装する場合は,

n = 5

for i in range(n):
print i
# 0
# 1
# 2
# 3
# 4

または,

n = 5

for i in xrange(n):
print i
# 0
# 1
# 2
# 3
# 4

のように書くのが一般的.

ここで,range(n)xrange(n)は,それぞれ,0からnまでの整数を昇順に並べたlistオブジェクト,xrangeオブジェクトを返す.

xrangeオブジェクトは,遅延評価を用いることで,値が必要とされるときに取り出すことの出来るオブジェクト.

nが非常に多くなる場合,range(n)ではリストを生成してからループを行うため,メモリ使用量が大きくなってしまうが,xrange(n)ではそれが避けられる.

また,速度についても,一部の場合を除いてxrange()の方が高速.

python - Should you always favor xrange() over range()? - Stack Overflow

また,(x)rangeでは,第2,第3引数を用いたり,reversed()を用いることで,いろいろな範囲の表現ができる.

# range(start, stop)で,startからstop-1までの整数すべてを昇順に並べたリストを返す

print range(2, 6) # [2, 3, 4, 5]

# range(start, stop, step)で,startからstepおきに値を増やしていって得られる整数の内,stop-1までのすべてのものを昇順に並べたリストを返す
print range(5, 30, 5) # [5, 10, 15, 20, 25]

# reversed()でリストを逆順にできる
for i in reversed(range(5)):
print i
# 4
# 3
# 2
# 1
# 0


for文での変数の展開

for文で,

l = [1, 2, 3, 4, 5]

for e in l:
print e


output

1

2
3
4
5

のように,リストの各要素を展開できるが,これは,

l = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]

for i, e in l:
print '#{0}: #{1}'.format(i, e)


output

0: a

1: b
2: c
3: d

のようにもできる.


enumerate

forループを回す際,リストのインデックスと値が同時に取得できるといい場合がある.

enumerate()は,引数のリストに対して,インデックスとその値を持つイテレータを返す.

l = ['a', 'b', 'c', 'd']

for elem in enumerate(l):
print elem
# (0, 'a')
# (1, 'b')
# (2, 'c')
# (3, 'd')

# 上のコードは下記のコードと等価
for i in range(len(l)):
print (i, l[i])


for-else,while-else文

Pythonでは,for文,while文にelse節を加えることができる.

この際,else節は,ループ終了までに一度も内部でbreakされなかった場合のみ呼び出される.

a = [1, 2, 3, 4, 5]

b = [1, 2, 4, 5]
x = 3

def find_val(l, x):
for i in range(len(l)):
if l[i] == x:
print i
break
else:
print 'Not found...'

# 上のfind_val()と等価なコード
def find_val2(l, x):
flag = False
for i in range(len(l)):
if l[i] == x:
print i
flag = True
break
if not flag:
print 'Not found...'

find_val(a, x) # 2
find_val(b, x) # Not found...

「xを探せ.見つからなかった時は'hoge'を出力しろ」みたいな設問の際,フラグを持つ必要が無いため,非常に書きやすくて便利.

ただし,ループが多重になる場合はかえって見通しが悪くなるため,使わない方がよい.