【Python】 Python ~ 基本編 / 辞書・あれこれ ~

■ はじめに

https://dk521123.hatenablog.com/entry/2019/10/12/084943
https://dk521123.hatenablog.com/entry/2019/10/27/100014

の続き。

今回は、ディクショナリ(辞書) (Dictionary) の操作をまとめる。
以下のサイトも役に立ちそう。

https://qiita.com/fujine/items/6c4c9dcdca10c6c09d52

目次

【1】マッピング
【2】zip : リスト型(list)=> 辞書型(dictionary)
【3】逆引き辞書を作成するには
【4】削除 del
【5】キーでソートする
【6】辞書リストをソートする
【7】辞書更新
【8】辞書をマージする
【9】初期値設定 - fromkeys
【10】複数一気に取得 - itemgetter
【11】読み取り専用にする - types.MappingProxyType

【1】マッピング

# Key(国コード) から値(主要都市)のマッパー
mapper = {
  "US" : ["NY", "LA"],
  "JP" : ["Tokyo", "Osaka"],
  "AU" : ["Sydney", "Adelaide"],
}

# ['NY', 'LA']
print(mapper.get("US"))
# ['Tokyo', 'Osaka']
print(mapper.get("JP"))
# ['Sydney', 'Adelaide']
print(mapper.get("AU"))
# ['Tokyo', 'Osaka']
print(mapper.get("JP", []))
# []
print(mapper.get("ZZ", []))

【2】zip : リスト型(list)=> 辞書型(dictionary)

zip については、以下の関連記事を参照。

https://dk521123.hatenablog.com/entry/2019/08/25/000330
構文

# リスト型(list)=> 辞書型(dictionary)
辞書 = dict(zip([リスト1], [リスト2])

サンプル

例1

ids = ['1', '2', '3']
names = ['Mike', 'Tom', 'Sam']

for id, name in zip(ids, names):
  print(f"id = {id}, name = {name}")
# id = 1, name = Mike
# id = 2, name = Tom
# id = 3, name = Sam

mapper = dict(zip(ids, names))
print(mapper)
# {'1': 'Mike', '2': 'Tom', '3': 'Sam'}

例2

keys = ["JP", "AU", "US"]
values = ["JAPAN", "AUSTRALIA", "UNITED STATES"]

mapper = dict(zip(keys, values))
for key, value in mapper.items():
  print(key + " " + value)
# JP JAPAN
# AU AUSTRALIA
# US UNITED STATES

【3】逆引き辞書を作成するには

https://www.youtube.com/watch?v=v1rUoMZRjoQ

でエニグマ暗号を扱っている際に、
逆引き辞書を作成していたので、メモ。

構文

逆引き辞書 = {値: キー for キー, 値 in 対象辞書.items()}

サンプル

keys = ["JP", "AU", "US"]
values = ["JAPAN", "AUSTRALIA", "UNITED STATES"]
mapper = dict(zip(keys, values))
print(mapper)
# {'JP': 'JAPAN', 'AU': 'AUSTRALIA', 'US': 'UNITED STATES'}

# 逆引き
backward_mapper = {value: key for key, value in mapper.items()}
print(backward_mapper)
# {'JAPAN': 'JP', 'AUSTRALIA': 'AU', 'UNITED STATES': 'US'}

【4】削除 del

del cities["Korea"]

# 列挙
fruits = ["apple","grape","banana"]
for index, value in enumerate(fruits):
    print("index:" + str(index) + " " + value) # "index:0 apple"... が出力

【5】キーでソートする

以下の動画ででてきたコードが勉強になったのでメモ

https://www.youtube.com/watch?v=WGSytLSi628&t=8s
サンプル

import collections

map1 = {"a": 1, "b": 2}
map2 = {"b": 4, "a": 3}

def sorted_by_ket(target_dict):
  return collections.OrderedDict(
    # 辞書のキー&値を取り出す
    sorted(target_dict.items(),
    # dict[0]=キー値でソート
    key=lambda dict: dict[0]))

print(str(sorted_by_ket(map1)))
print(str(sorted_by_ket(map2)))

出力結果

OrderedDict([('a', 1), ('b', 2)])
OrderedDict([('a', 3), ('b', 4)])

【6】辞書リストをソートする

以下のサイトが参考になった

https://stackoverflow.com/questions/1143671/python-sorting-list-of-dictionaries-by-multiple-keys
サンプル

dict_list = [
  {"no":12, 'name': 'Tom', 'total': 96.0},
  {"no":10, 'name': 'Smith', 'total': 34.0},
  {"no":10, 'name': 'Tim', 'total': 34.0},
  {"no":11, 'name': 'Ammy', 'total': 100.0},
]

sorted_dict_list = sorted(
  dict_list, key=lambda dic: (-dic['total'], dic['no'], dic['name']))

for info in sorted_dict_list:
  print("{} {} {}".format(
    info['total'], info['no'], info['name']))

出力結果

100.0 11 Ammy
96.0 12 Tom
34.0 10 Smith
34.0 10 Tim

【7】辞書更新

demo_dict = {"a": 1}

# 更新
demo_dict["a"] *= 2
print(demo_dict["a"])  # 2

例1:辞書リストの値を一部書き換える

dict_list = [
  {"no":12, 'name': 'Tom'},
  {"no":10, 'name': 'Smith'},
  {"no":10, 'name': 'Tim'},
  {"no":11, 'name': 'Ammy'},
]

# 'no=11'の場合に名前を書き換える
replaced_dict_list = \
  [{'no': x['no'], 'name': 'Kevin'} if x['no'] == 11 else x for x in dict_list]

# [{'no': 12, 'name': 'Tom'}, {'no': 10, 'name': 'Smith'}, 
#  {'no': 10, 'name': 'Tim'}, {'no': 11, 'name': 'Kevin'}]
print(replaced_dict_list)

辞書更新

demo_dict = {"a": 1}

# 更新
demo_dict["a"] *= 2
print(demo_dict["a"])  # 2

【8】辞書をマージする

[1] updateメソッド
[2] dict関数
[3] collections.ChainMap
[4] | 演算子 / |=演算子

参考文献
https://www.python.ambitious-engineer.com/archives/1763
https://note.nkmk.me/python-dict-merge/

[2] dict関数

* 以下の関連記事でも利用

Python ~ 基本編 / YAML
https://dk521123.hatenablog.com/entry/2019/10/16/225401
[4] | 演算子 / |=演算子

# Python3.9以降
dict1 = {"a":1, "b":2}
dict2 = {"c":3, "d":4}

dict3 = dict1 | dict2
print(dict3) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}

【9】初期値設定 - fromkeys

keys = ("a", "b", "c")

print({}.fromkeys(keys))        # {'a': None, 'b': None, 'c': None}
print({}.fromkeys(keys, 0))     # {'a': 0, 'b': 0, 'c': 0}
print({}.fromkeys(keys, "-"))   # {'a': '-', 'b': '-', 'c': '-'}
print({}.fromkeys(keys, False)) # {'a': False, 'b': False, 'c': False}

【10】複数一気に取得 - itemgetter

from operator import itemgetter

demo_dict = {"a": 1, "b": 3.14, "c": []}

print(itemgetter("a")(demo_dict))            # 1
print(itemgetter("a", "b")(demo_dict))       # (1, 3.14)
print(itemgetter("c", "b", "a")(demo_dict))  # ([], 3.14, 1)

【11】読み取り専用にする - types.MappingProxyType

from types import MappingProxyType

demo_dict = {"a": 1, "b": 3.14, "c": []}
readonly_dict = MappingProxyType(demo_dict)

readonly_dict["a"] = 2 # Error
# TypeError: 'mappingproxy' object does not support item assignment

関連記事

Python ~ 基本編 / リスト ~
https://dk521123.hatenablog.com/entry/2019/10/12/084943
Python ~ 基本編 / タプル・集合 ~
https://dk521123.hatenablog.com/entry/2019/10/26/000000
Python ~ 基本編 / ラムダ lambda ~
https://dk521123.hatenablog.com/entry/2019/09/23/000000
Python ~ 基本編 / 文字列 ~
https://dk521123.hatenablog.com/entry/2019/10/12/075251
Python ~ 基本編 / astモジュール ~
https://dk521123.hatenablog.com/entry/2021/10/01/000000