最近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ベストプラクティス・パターン―シンプル・デザインへの宝石集
- 作者: ケントベック,Kent Beck,梅沢真史,皆川誠,小黒直樹,森島みどり
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2003/03
- メディア: 単行本
- 購入: 7人 クリック: 94回
- この商品を含むブログ (55件) を見る