import collections
word_count = collections.defaultdict(int)
for word in ["foo", "bar", "foo", "foobar"]:
word_count[word] += 1
print word_count
# >>> defaultdict(<type 'int'>, {'foobar': 1, 'foo': 2, 'bar': 1})
辞書型にどんなキーが与えられるかわからない場合に,存在しないキーだったらfooで初期化する,という状況はよくあり,collections.defaultdictがそれを満たしてくれます.defaultdict(int)
とすると↑のように初めてのアクセスで0に初期化してくれるわけですが,これは結局どういうことかというと
import collections
word_count = {}
for word in ["foo", "bar", "foo", "foobar"]:
if not word in word_count:
word_count[word] = int()
word_count[word] += 1
print word_count
これと同じ処理になるわけです.結局引数なしの関数で何らかの値を返すものであればいいわけですね.だからlambdaを使ってdefaultdict(lambda: [])
とかしてやると結構わかりやすい.追記: この空リストを生成する例だと,lambdaを使うまでもなくlist()を渡したほうが読みやすいです.lambdaを使うべきは下のようなもう少し複雑な例.
さっきの例を発展させると,各アルファベットの出現頻度を数えるとかもできます.
import collections
word_count = collections.defaultdict(lambda: [0 for i in range(26)])
for word in ["foo", "bar", "foo", "foobar"]:
for chara in word:
word_count[word][ord(chara)-ord("a")] += 1
print word_count
# >defaultdict(<function <lambda> at 0x10e5147d0>, {'foobar': [1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], 'foo': [0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'bar': [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]})
defaultdict()自体もdefaultdictを返すわけで,defaultdict(defaultdict(lambda: {"name": "null", "age": 20}))
とかももちろんできます.