Python小ネタシリーズ。
- Pythonネタのときは基本的にPython3を想定しています。
- また >>> はインタプリタ実行だけど、入り混じってます。適当にどうぞ。
今回はcollectionsというモジュール、defaultdictとCounterについて。ChainMapなんていうのもあるけどお手軽に使えるやつをということで。
通常のディクショナリは、存在しないキーを参照しようとした場合、KeyErrorが発生する
※代入しようとした場合、それは初期化になるのでエラーにならない
>>> d_normal = {} >>> d_normal["noexist"] += 1 Traceback (most recent call last): File "", line 1, in KeyError: 'noexist'
defaultdictの仕組みを使うと、例えばint型の値を使うディクショナリ(風のdefaultdictオブジェクト)を使うことで存在しないキーをいきなり使うことができる(存在しない時のデフォルト値が、型によって補填される。intなら0。)
>>> from collections import defaultdict >>> d_default = defaultdict(int) >>> d_default["noexist"] += 1 >>> d_default["noexist"] 1
これを使うと、例えばこんなデータについて
apple orange apple orange orange grape apple grape
それぞれの個数を調べる、なんていう事がしたいような時、こんなディクショナリを作りたいよねと。
{ "apple": 3, "orange": 5, "grape": 2 }
下準備。まずリストにする。
data = """apple orange apple orange orange grape apple grape""".splitlines()
空のディクショナリを作って・・・
fruits = {}
通常ならこんな風にキーがなかったら0をセットする
for fruit in data:
# もしディクショナリ内に既に存在すれば
if fruit in fruits.keys():
# 1個追加する
fruits[fruit] += 1
# もしディクショナリ内に存在しなければ
else:
# 1個目を入れる
fruits[fruit] += 1
>>> fruits
{'apple': 3, 'orange': 3, 'grape': 2}
これを、defaultdictを使うと、こんなにもシンプルに書ける。
fruits = defaultdict(int) for fruit in data: fruits[fruit] += 1 >>> fruits defaultdict(<class 'int'>, {'apple': 3, 'orange': 3, 'grape': 2})
しかしこれくらい単純な個数計算であれば、同じcollectionsモジュールにCounterというものが用意されていて、リストぶちこむだけで同じ事が実現できてしまう。
>>> from collections import Counter >>> counts = Counter(data) >>> counts Counter({'apple': 3, 'orange': 3, 'grape': 2})
Counterオブジェクトのほうが他にも機能があり、例えばトップ〇のキー/ペアを取得するmost_commonなんていうメソッドがある。
>>> counts.most_common(2)
[('apple', 3), ('orange', 3)]
また、Counterクラスのオブジェクトはdictクラスの子クラスなので、dictが備えている機能は備えている。
Help on class Counter in module collections:
class Counter(builtins.dict)
| Dict subclass for counting hashable items. Sometimes called a bag
| or multiset. Elements are stored as dictionary keys and their counts
| are stored as dictionary values.
通常のディクショナリのように値を取り出せるし、
>>> counts["apple"]
3
値だけ取り出したり。
>>> counts.values()
dict_values([3, 3, 2])
キーだけ取り出したり。
>>> counts.keys()
dict_keys(['apple', 'orange', 'grape'])
Counterクラスは演算子オーバーロードもされているので、オブジェクト同士を足したりなんだりができる。
>>> c1 = Counter("aaaaabbbbb") >>> c1 Counter({'a': 5, 'b': 5}) >>> c2 = Counter("bbbbbccccc") >>> c2 Counter({'b': 5, 'c': 5}) >>> c1 + c2 Counter({'b': 10, 'a': 5, 'c': 5}) >>> >>> c1 - c2 Counter({'a': 5}) >>>
結論:べんり。