【Python文法】アルゴリズム実装で多用する記法


はじめに

Pythonでアルゴリズムを実装する際によく使う書き方や他言語であまり見かけない便利だった書き方の備忘録です。
注 ) 執筆途中です。ちょっとずつ増えます。
注 ) Pythonをほぼ趣味で使っております。業務で用いていたりアルゴリズムPythonガチ勢というわけではございません。ご了承を。

基本的に標準ライブラリのみを用いております。numpy などは用いません。
面倒だったのでまだスライス関係やリスト内包表記はありません。

演算子

インクリメント

他言語でよく見る i++ のようなインクリメント(/デクリメント)記法が存在しない。

i += 1

あくまでこのような記法。

掛け算と累乗

2 * 3    # print(2 * 3) => 6

アスタリスク1つ * で多言語同様、通常の掛け算。

2 ** 3    # print(2 ** 3) => 8

アスタリスク2つ ** で累乗を行う。

割り算

Pythonには浮動小数点を残す割り算と切り捨てる割り算が存在する。

5 / 2    # print(5 / 2) => 2.5

スラッシュ1本 / のみで浮動小数点を残す。
(演算結果が必ず float型 となる)

5 // 2    # print(5 // 2) => 2

スラッシュ2本 // で切り捨てを行う。
( int / int の場合は演算結果が int型 に、 それ以外の場合は演算結果がすべて float型 に)

リスト関連

Pythonのリストに関する for文の特徴として、インデックス番号ではなくリストの要素値そのものを周回することができるというものがある。

リスト周回の基本 (value)

for val in data:

val にリストの中身の各値が定義される。
例 ) data = [2, 4, 6, 8] : print(val) => 2, 4, 6, 8

リスト周回の基本 (index)

for i in range(len(data)):

i にリストの中身のインデックス番号が定義される。
インデックス番号は i = 0 から始まる。
例 ) data = [2, 4, 6, 8] : print(i) => 0, 1, 2, 3

[補足] len()関数 について
len関数は、引数にリストを渡すとそのリストのサイズを返す。
例 ) data = [2, 4, 6, 8] : print(len(data)) => 4

[補足] range()関数 について
range関数は、for文でシーケンスを生成する。
第一引数:start値
第二引数:[必須] end値
第三引数:step値
第一、第三引数は省略可能。これらを用いた使用方法は次項目等で。

リスト周回 (開始を指定)

for i in range(3, len(data)):

range()関数に第一引数を定義することで開始位置を指定可能。
開始位置はインデックス番号 i = 0 から始まる。
例 ) data = [2, 4, 6, 8] : print(i) => 1, 2, 3

これを用いることで

for i in range(len(data)):
    for j in range(i, len(data)):

のような計算量の高いソートで多用する書き方が可能。

リスト周回 (逆順value)

for v in reversed(data):

reversed()関数を用いることで v に逆順でリストの中身の各値を定義する。
例 ) data = [2, 4, 6, 8] : print(v) => 8, 6, 4, 2

リスト周回 (逆順index)

for i in range(len(data), 0, -1):

range()関数の第三引数を用いることで i に逆順でインデックス番号を定義する。
[注] 開始位置と終了位置が通常と異なることに注意。range(0, len(data), -1) とならない。
[注] 第一、第二引数を無視(省略やアンダースコア使用等)することは不可。
例 ) data = [2, 4, 6, 8] : print(i) => 3, 2, 1, 0

[補足] renge()関数に関する注意事項

range関数の第二引数は、終了index番号ではなく、長さ。

例) data = [2, 4, 6, 8]
  その1. renge(0, 3) print(i) => 0, 1, 2
  その2. renge(0, 4) print(i) => 0, 1, 2, 3
  その3. renge(0, len(data)) print(i) => 0, 1, 2, 3

このように、renge()関数でend値を指定するときは注意が必要。

ミス無くすべて周回したいときは、len()関数を用いるのが無難。

(Pythonのリストを参照する際に pointer0-value0--pointer1-value1--pointer2-value2 というイメージを持つと間違いづらくなる。)

[追記] 友人が「これってCで言うこの書き方のbだよね」って言ってました。
for(i = a; i < b; i++)
それだ。強い。

リスト周回 (value, index の両方使用)

for i, v in enumerate(data):

enumerate()関数を用いることで i にインデックス番号、v にリストの中身の各値を定義する。
[注] 第一返値:index、第二返値:value
例 ) data = [2, 4, 6, 8] : print(i, v) => 0 2, 1 4, 2 6, 3 8

制御構文

if文の比較演算子 in / not in

if val in データ構造:
if val not in データ構造:

データ構造に値が入っている / 入っていないときに発火するif文記法。
in / not in 自体は比較演算子のため、if文以外でも使用可能。
[注] データ構造がリストの場合、O(n) となるらしく少し遅い。

while文による無限ループ

while True:

while文の条件式にboolean値の True を入れることで無限ループとなる。
Trueであればなんでも良いので、一応なんでも可能。1 など。

[補足] boolean値について
Python は True1 が boolean における True。
また、False0 が False。

関数

関数アノテーション

def 関数名(引数a:, 引数b:) -> 返り値の型:

関数の省略記法。ちょっとしたアロー関数。

綺麗なコード

スワップ

x, y = y, x

C言語を始めとした通常の言語における tmp = x; x = y; y = tmp; のような値交換を1行で書くことができる。

チェーン

-2 <= x <= 10

不等号の大なり小なりをまとめて書くことができる。

これを踏まえて右の記法は良くない。x <= -2 and x >= 10

入力関連

コマンドライン引数受付

import sys
value1 = sys.argv[1]
value2 = sys.argv[2]

標準ライブラリ sys をインポートすることで使用可能。
最初のコマンドライン引数が 1、次が 2 となる。0 始まりではない。

おわりに

通常ではあまり使わないけれどもアルゴリズム実装においては汎用性の高い記法等がございましたらぜひ教えてください。Pythonも奥が深いです。