"BOKU"のITな日常

還暦越えの文系システムエンジニアの”BOKU”は新しいことが大好きです。

Pythonで頻繁に使う辞書型(dictionary)(連想配列)の初期化・追加・一覧のスマートな方法を整理しときます

Pythonの辞書(dictionary)は、やたらと使います。

他の言語だと、連想配列と呼んだりもします。

ようするに、文字列をキー(添え字)にして値を管理できるデータ構造です。

これも、ちょっと癖があって、しばらく離れると忘れがちなので、整理しときます。

f:id:arakan_no_boku:20181124131221j:plain

 

まずは初期化のデータの追加

 

まずは、一般的な辞書。

割りとよくある「文章等を単語に分割して、その単語の出現頻度を数えるために辞書でカウントアップする」みたいな用途を想定した例です。

追加の仕方でよく使う3パターンを書いてます。

seed = ['apple','orange','banana','orange','banana','apple','apple','apple']
md = {}
for key in seed:
    if key not in md:
        md[key] = 0
    md[key] += 1

md2 = {}
for key in seed:
    md2.setdefault(key,0)
    md2[key] += 1

md3 = {}
for key in seed:
    md3[key] = md3.get(key,0) + 1

ポイントは、一般的な辞書(dictianary)の場合、単純に「md[key] += 1  」だけすると、存在しないキーでエラーで落ちる(=1件目からエラーになる)ということです。

なので。

キーの存在チェックをして、なければ先に代入する(上の例)か、または、「setdefault()」を使う(下の例)かの方法をとることになります。

「setdefault()」はキーが存在しないとキー追加と代入をして、すでにあるキーの場合はそのままにしてくれるので大丈夫なわけです。

まあ・・。

これでも良いのですけど、perlとかで連想配列を覚えた人間にとっては、ちょっと面倒くさくて不満です。

やっぱ、「md[key] += 1」だけで、キーがない時は、自動的に0をセットしてほしい。

なので、自分は一般的な辞書ではなく、デフォルト辞書をよく使います。

from collections import defaultdict

seed = ['apple','orange','banana','orange','banana','apple','apple','apple']

md = defaultdict(int)
for key in seed:
    md[key] += 1

違いは初期化の仕方だけです。 

① collectionsモジュールのdefaultdictクラスをインポートする。

② defaultdict()で初期化する。

これだけで、上記のようにスマートにカウントできるようになります。

ちなみに、defaultdictクラスの引数のintは、デフォルト値「0」を返す関数です。

変数ではないです。 

 

辞書にセットしたキーや値をすべて参照する

 

個別のキーから値を取得するやり方です。

例えば。

info = {'apple':'りんごだよ','orange':'みかんだよ','banana':'ばななだよ'}

みたいな辞書を初期化で展開しておいたなら。

info['apple']

で「りんごだよ」の文字列を得るみたいな感じです。

今度は。

辞書に格納したすべてのキーと値を一覧するやり方です。

キーの一覧(リスト)は、「keys()」で取得できます。

値の一覧(リスト)は、「values()」で取得できます。

これをzip()と組合せて使うと、結構スマートに書けます。

なお、例は「デフォルト辞書」を使ってます。

初期化が違うだけで、参照の方法は「通常の辞書」でも同じです。

from collections import defaultdict

seed = ['orange','banana','apple','apple','apple','apple','orange','banana','banana','banana','banana','banana']

md = defaultdict(int)
for key in seed:
    md[key] += 1

for key,val in zip(md.keys(),md.values()):
    print(key,":",val)

これで以下のような結果が表示されます。

orange : 2
banana : 6
apple : 4

でも、そのままだと並びがランダムです。

ソートする場合は、一度辞書をソートしてから、上記の要領で一覧処理します。

キー・値でソートする例(昇順・降順)です。

from collections import defaultdict

seed = ['orange','banana','apple','apple','apple','apple','orange','banana','banana','banana','banana','banana']

md = defaultdict(int)
for key in seed:
    md[key] += 1

# キーの昇順にソートする
smd1 = dict(sorted(md.items(),key=lambda x:x[0]))
for key,val in zip(smd1.keys(),smd1.values()):
    print(key,":",val)

# キーの降順にソートする
smd2 = dict(sorted(md.items(),key=lambda x:x[0],reverse=True))
for key,val in zip(smd2.keys(),smd2.values()):
    print(key,":",val)

# 値の昇順にソートする
smd3 = dict(sorted(md.items(),key=lambda x:x[1]))
for key,val in zip(smd3.keys(),smd3.values()):
    print(key,":",val)

# 値の降順にソートする
smd4 = dict(sorted(md.items(),key=lambda x:x[1],reverse=True))
for key,val in zip(smd4.keys(),smd4.values()):
    print(key,":",val)

この結果は上から順にこんな感じ。

apple : 4
banana : 6
orange : 2 

 orange : 2
banana : 6
apple : 4

orange : 2
apple : 4
banana : 6 

banana : 6
apple : 4
orange : 2 

いちおう、これで十分です。

でも。

自分的には「 key=lambda x:x[1]」の部分が、いまいち好きでありません。

好みの問題だけですけど。

なので、自分はopratorモジュールのitemgetter()を使うやり方を最近は使ってます。

一応、そちらも書いておきます。

from collections import defaultdict
import operator as op

seed = ['orange','banana','apple','apple','apple','apple','orange','banana','banana','banana','banana','banana']

md = defaultdict(int)
for key in seed:
    md[key] += 1

# キーの昇順にソートする
smd1 = dict(sorted(md.items(),key=op.itemgetter(0)))
for key,val in zip(smd1.keys(),smd1.values()):
    print(key,":",val)

# キーの降順にソートする
smd2 = dict(sorted(md.items(),key=op.itemgetter(0),reverse=True))
for key,val in zip(smd2.keys(),smd2.values()):
    print(key,":",val)

# 値の昇順にソートする
smd3 = dict(sorted(md.items(),key=op.itemgetter(1)))
for key,val in zip(smd3.keys(),smd3.values()):
    print(key,":",val)

# 値の降順にソートする
smd4 = dict(sorted(md.items(),key=op.itemgetter(1),reverse=True))
for key,val in zip(smd4.keys(),smd4.values()):
    print(key,":",val)

ちょっとだけ見やすくなった気がするのは自分だけですかね(笑)

今回は、辞書の初期化・追加・一覧で、自分が久しぶりの時に忘れがちなポイントだけを、備忘をかねて整理してみました。

ではでは。