コンピューターサイエンス入門:理論編
map で出現回数を数える
この回でやること
エラーログの集計を読み解き、辞書のキーごとの件数と初期値の扱いを確かめます。
- 読む 約 7 分
- 最後にクイズ 1 問
エラーコードごとの件数を知る
ログからエラーごとの件数を数えます。timeout 用と not_found 用の変数なら、既知の2種類は数えられます。しかし本番のログには未知のコードも混ざり、この形では数え落とします。
未知の種類も数えられるよう、コードから件数を引ける表を使います。この対応表をマップと呼び、Python では辞書を使います。
キーごとに、小さなカウンタを持つ
キーは調べる手掛かり、値は対応する情報です。ここではコードをキー、回数を値にします。timeout を増やしても not_found の件数は変わりません。
Python
counts = {}
counts["timeout"] = counts.get("timeout", 0) + 1
counts["timeout"] = counts.get("timeout", 0) + 1
counts["not_found"] = counts.get("not_found", 0) + 1
print(counts) # {'timeout': 2, 'not_found': 1}get(キー, 0) は、キーがあれば今の値を返し、なければ0を返します。そこに1を足して同じキーへ保存します。初めてのコードは 0 + 1 = 1件、次は 1 + 1 = 2件です。新しいコードも同じ手順で数えられます。
無いキーと、0件は違う
Python の辞書で存在しないキーに直接 += 1 を行うと、今の値を読む段階で止まります。JavaScript の通常のオブジェクトでは、存在しない値は undefined で、そこへ1を足すと NaN になります。
集合は「出たかどうか」を覚えますが、辞書は「何回出たか」も持てます。3回出たコードを集合へ3回追加しても、回数3は残りません。
集計の後で最多を調べる
辞書の読み書きは平均 O(1) です。n行のログを数え、k種類の表から最大の件数を探すと、平均 O(n + k)。kはn以下なので、全体では平均 O(n) です。件数を増やすたびに最大値も更新する方法でも、同じ最多件数が分かります。
例題で確かめる
ログが timeout、not_found、timeout、busy、timeout の順に5行届きます。各行を数えた直後の件数を追います。
| 読んだコード | timeout | not_found | busy |
|---|---|---|---|
| timeout | 1 | 0 | 0 |
| not_found | 1 | 1 | 0 |
| timeout | 2 | 1 | 0 |
| busy | 2 | 1 | 1 |
| timeout | 3 | 1 | 1 |
表の0は、まだ出ていないことを示します。最多は timeout の3件です。合計も 3 + 1 + 1 = 5件で、読んだ行数と一致します。