Google Code Jam で得た Python の tips(1)

2ヶ月前は全く Python を使えなかった私ですが、Google Code Jam の勉強を通して随分色々な技術を学ぶことができました。
ここにまとめておきます。

あまりに長くなりすぎたので3分割しました。

目次

Part1(この記事)
Part2
  • リスト
Part3
  • 数学
  • ビット演算
  • 条件式
  • ループ
  • 例外処理
  • その他
  • おまけ:今回のテンプレート

ファイル

標準入力から読み込む

一度に最後まで読み込みたい場合は以下のようにする。

import sys
for line in sys.stdin:


1行の場合は raw_input() が簡単。
こちらは末尾に改行が入らない。

A = raw_input()
標準出力、標準エラー出力に書き出す

print は改行が入る。

print "some text"


カンマをつければ改行は入らないが空白が入る。

print "some text",


改行も空白も入れたくなければ sys.stdout を使う。

import sys
sys.stdout.write("some text")


標準エラー出力は sys.stderr。
GCJ では、zibada が以下のようなテンプレートを作っている。
(出典:GCJ 2010 QR-A zibada)

def dbg(a): sys.stderr.write(str(a))


便利。私は改行を足して使っている。

with によるファイルのオープン
with open("myfile.txt") as f:
    for line in f:
        print line


行の処理中に何か問題が発生しても、最後にはかならずファイルが閉じられる。

出典:404 Not Found

文字列

文字列をリストに分割する
(A,B,C) = raw_input().split()


全部整数として読み込みたい場合は map を使う。

(A,B,C) = map(int,raw_input().split())


GCJ では、zibada は2つの関数を作っている。
1つ目は GCJ 2009 1C-B zibada より。

def readlinearray(foo): return map(foo, raw_input().split())


もう1つは GCJ 2010 QR-A zibada より。

def readarray(foo): return [foo(x) for x in raw_input().split()]


なぜこのような変更をしたのか不明。出力はどちらも同じはず。

文字列の長さ
len(str)
ASCIIコードと文字の相互変換

以下のコードはそれぞれ 70, F を返す。

print ord('F')
print chr(70)


余談だが、linux 使っているときに ASCII コード調べたければ man ascii で一覧が出る。
案外知らない人多いと思う。

スペースを入れずに文字列を連結
print "aaa" + "bbb" + str(123)


プラスを使えばいい。ただし、連結対象は全て文字列でなければならない。
上のコードで 123 をそのまま使うとエラーになる。
よく忘れるので注意すること。

ループで1文字づつ展開する
for c in word:


これで1文字づつ取り出せる。

php の join() や ruby の Array.join() のように join を使う。

phpruby と違い、python のリストには join() がない。
しかし、以下の形で文字列として連結することができる。

s.join(q)


ここで s は文字列、q はシーケンス。つまりリストでも構わない。
s が区切り文字になるので、例えば空文字で ''.join(q) のように書けば、完全に並んだ文字列にしてくれる。
ただし、シーケンス中の要素は全て文字列でなければいけない。
たまに整数のリストをそのまま join しようとしてはまることがある。
そういうときは map() でも一枚噛ましてやればいい。

出典:3.6.1 文字列メソッド

lstrip,rstrip,strip

それぞれ行頭、行末、その両方から特定の文字を除去したコピーを返す。
指定しない場合は空白文字全て。
引数は文字列で指定し、そこで指定された全ての文字が除去される。順序は無視。

出典:3.6.1 文字列メソッド

正規表現

re.match と re.search

search を使うと、開始位置が文字列中にあってもマッチする。
match の場合はきちんと文字列中にあることを明示しない限りマッチしない。
逆に言うと、先頭にだけマッチさせたい場合は match で書く方が簡単。

後方参照

\\1 とすること

置換
p = re.compile(regexp)
line = p.sub(replace,target_str)

辞書

ループで添字も一緒に取り出す
for k,v in dict.iteritems():
ループ時に value でソート
for k, v in sorted(d.items(), key=lambda x:x[1]):
    print k, v


出典:Pythonの辞書(dict型)をvalue値でソート - プログラミング工場 / Python

get()

dict[key] という形式で存在しないキーを指定すると KeyError が出される。
しかし dict.get(key) とすれば、キーが存在しないときに None を返す。
dict.get(key,x) とした場合、キーが存在しないときに None ではなく x を返す。

出典:404 Not Found

タプル

値の交換
(a,b) = (b,a)


出典:GCJ2010 QR-B zibada

内包表記

タプルで渡せば辞書の内包表記ができる。

dict( (k,k*2) for k in xrange(10))


Part1 / Part2 / Part3