SE_BOKUのまとめノート的ブログ

SE_BOKUが知ってること・勉強したこと・考えたことetc

辞書(連想配列)の初期化・代入・ループ・ソート/Python文法

f:id:arakan_no_boku:20181124131221j:plain

目次

辞書(連想配列)の初期化・代入・ループ・ソート/Python文法

Pythonの辞書(dictionary)は数値以外に 文字列などもキーにできます。

ほかの言語で「MAP」とか「連想配列」と呼ばれるものと同じように使えます。

辞書のの基本操作(初期化・追加・一覧・ソート)をまとめます。

初期化

空で初期化 

空で初期化するだけなら簡単です。

dic={}

一次元で静的にキー:値のセットで初期化

一次元で静的に値を与えて初期化するなら。

dic={ 'A': 'VVV1', 'B', 'VVV2' } 

 のように、「’KEY': 'VALUE'」の組合せで初期値を与えます。

二次元以上(ネストする)の辞書の初期化は長くなるので別記事にしました。

arakan-pgm-ai.hatenablog.com 

キーと値の操作

キーの追加・値の代入

辞書は「辞書[キー] = 値」のようにしてキーの追加と値の代入ができます。

辞書の名前を、仮にmdとすると・

md["apple"]=2

とすると「"apple"」というキーがなければ追加されますし、あれば上書きされます。

代入した値は

md["apple"]

で参照できます。

辞書の値を計算で使う場合の注意点

辞書の代表的な使い方で、単語の出現数をカウントするというものがあります。

単語(例えば"apple")をキーにするなら、以下のようにインクリメントできます。

md["apple"] += 1  

しかし、一般的な辞書(dictianary)では、存在しないキーを指定してインクリメントなどをするとエラーになります。 

その問題回避の方法としては4通り。

  • キーの存在チェックをして、なければキーを追加してからインクリメントする
  • setdefault()してからインクメントする
  • get()(存在しない指定したデフォルトを返す)してからインクリメントする
  • デフォルト辞書(defaultdict)を使う

です。

上の3つを実装サンプルにすると、以下のようになります。

seed =
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

# setdefaultを使う方法
md2 = {}
for key in seed:
    md2.setdefault(key, 0)
    md2[key] += 1

# get()(存在しないキーだと指定したデフォルトを返す)で取得してから加算する
md3 = {}
for key in seed:
    md3[key] = md3.get(key, 0) + 1

 

デフォルト辞書(defaultdict)を使う場合は以下のようにします。

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

② defaultdict()で初期化する。

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

from collections import defaultdict

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

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

 

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

変数と勘違いしやすいので、ご注意ください。。 

デフォルト辞書は、普通の辞書と同じように使えますが、djangoテンプレートを使うときにデフォルト辞書を直接渡せない場合があるなど一部、制限事項があるので、そこを認識して使う必要があります。

辞書のキーと値をループで取得

方法は何通りかあります。

keys()/values()/items()

一番よく使う方法です。

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

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

キーと値をセットで取得するには「items()」で取得します。

for key,val in md.items():
    print(key,":",val)

みたいな感じです。

zip

items()と同じことを、「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

ソート

辞書のデフォルトのソート順は挿入順だけどバージョンに依存

辞書のソート順はバージョンに依存します。

Python3.7からは言語仕様で、標準の辞書でも挿入順が保証され、Python3.6でもCPythonの実装ベースで同様の動きをします。

しかし、それ以外だと保証されません。

キーの挿入順をバージョンに依存せず保証するクラス

バージョンにかかわらず、キーの挿入順を記録して、その順番で取り出せることを確実に保証したい時には「collectionsモジュールのOrderedDictクラス」を使います。

from collections import OrderedDict

od = OrderedDict()

 みたいに初期化して、あとは普通の辞書のように使えばよいです。

「od.items()」などで取り出した時に、キーの挿入順で取り出せます。

なんで、辞書の取り出し順がバージョンによって違うのかって話は、こちらの記事がすごいわかりやすかったので、リンク貼っておきます。

www.freia.jp 

キー・値でソート/lambda 式を使う 

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

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

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 

キー・値でソート/itemgetter() 

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)

ちがうのは「key=op.itemgetter(1)」の部分だけです。

以上、辞書の初期化・追加・一覧・ソートについて整理してみました。

ではでは。