歩いたら休め

If the implementation is easy to explain, it may be a good idea.

【Python】辞書のキーにデフォルト値をセットする

最近Python自然言語処理をしていて、複数のライブラリを利用していると、どうしてもリストや辞書のややこしい変換が増えてきます。

categories = ['サーバル', 'かばん', 'サーバル']
lines = [
    ['ここ', 'は', 'さばんな', 'ちほー'],
    ['食べ', 'ない', 'で', 'ください'],
    ['すっごーい!']
]

これを、キャラクターごとに利用している単語を集計したいと思います。具体的には、以下のような辞書に変換したいとします。

{
    'サーバル': ['ここ', 'は', 'さばんな', 'ちほー', 'すっごーい!'],
    'かばん': ['食べ', 'ない', 'で', 'ください']
}

Rubyであれば、nilガードを使って、サクッとハッシュの値を初期化すると思います。

# Ruby
categories.zip(lines).each_with_object({}) do |(c, l), hash|
  hash[c] ||= []
  hash[c].concat(l)
end

ところが、Pythonで同じことをやろうとすると、「キーが存在しないときに初期化する」という処理で、どうしても冗長になってしまいます。

result = {}
for c. l in zip(catagories, lines):
    if not c in result:
        result[c] = []
    result[c] += l

こんなときは、collections.defaultdictを使うと良さそうです。指定の型のデフォルト値(この場合は空のリスト)で初期化した値を辞書のキーに持たせることができます。

from collections import defaultdict

result = defaultdict(list)
for c, l in zip(catagories, lines):
    result[c] += l

厳密にはdict型ではないものの、defaultdictはdict型のサブクラスで、メソッドもほぼ共通しています。

参考:

8.3. collections — コンテナデータ型 — Python 3.6.1 ドキュメント

このような「オブジェクトの操作に向いているデータ型を使おう」といった感覚は、ケント・ベックSmalltalk本に詳しく書かれていました。

言語はSmalltalkですが、Pythonでもよく使われるSet型についての解説(値の重複チェックはオブジェクトにまかせてしまおう!)もあり、オブジェクトの操作の感覚をつかむのに勉強になりました。

ケント・ベックのSmalltalkベストプラクティス・パターン―シンプル・デザインへの宝石集

ケント・ベックのSmalltalkベストプラクティス・パターン―シンプル・デザインへの宝石集

  • 作者: ケントベック,Kent Beck,梅沢真史,皆川誠,小黒直樹,森島みどり
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2003/03
  • メディア: 単行本
  • 購入: 7人 クリック: 94回
  • この商品を含むブログ (55件) を見る