3-1. 辞書 (dictionary)¶
キーと値を対応させるデータ構造である辞書について説明します。
参考
辞書は、キー (key) と値 (value) を対応づけるデータです。 キーとしては、文字列・数値・タプルなどの変更不可能なデータを使うことができますが、 変更可能なデータであるリスト・辞書を使うことはできません。 (辞書も変更可能なデータです。) 一方、値としては、変更の可否にかかわらずあらゆる種類のデータを指定できます。
たとえば、文字列 'apple'
をキーとし値として数値 3
を、'pen'
をキーとして 5
を対応付けた辞書は、 次のように作成します。
[1]:
ppap = {'apple' : 3, 'pen' : 5}
ppap
[1]:
{'apple': 3, 'pen': 5}
[2]:
type(ppap)
[2]:
dict
辞書の キー1
に対応する値を得るには、リストにおけるインデックスと同様に、
辞書[キー1]
とします。
[3]:
ppap = {'apple' : 3, 'pen' : 5}
ppap['apple']
[3]:
3
辞書に登録されていないキーを指定すると、エラーになります。
[4]:
ppap['orange']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Cell In[4], line 1
----> 1 ppap['orange']
KeyError: 'orange'
キーに対する値を変更したり、新たなキーと値を登録するには代入文を用います。
[5]:
ppap = {'apple' : 3, 'pen' : 5}
ppap['apple'] = 10
ppap['pinapple'] = 7
ppap
[5]:
{'apple': 10, 'pen': 5, 'pinapple': 7}
上のようにキーから値は取り出せますが、値からキーを直接取り出すことはできません。 また、リストのようにインデックスを指定して値を取得することはできません。
[6]:
ppap[1]
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Cell In[6], line 1
----> 1 ppap[1]
KeyError: 1
キーが辞書に登録されているかどうかは、演算子 in
を用いて調べることができます。
[7]:
ppap = {'apple': 3, 'pen': 5}
'apple' in ppap
[7]:
True
[8]:
'banana' in ppap
[8]:
False
組み込み関数 len
によって、辞書に登録されている要素、キーと値のペア、の数が得られます。
[9]:
ppap = {'apple': 3, 'pen': 5}
len(ppap)
[9]:
2
del
文によって、登録されているキーの要素を削除することができます。具体的には、次のように削除します。
del 辞書[削除したいキー]
[10]:
ppap = {'apple' : 3, 'pen' : 5}
del ppap['pen']
ppap
[10]:
{'apple': 3}
空のリストと同様に空の辞書を作ることもできます。このような空のデータは繰り返し処理でしばしば使われます。
[11]:
empty_d = {}
empty_d
[11]:
{}
練習¶
リスト list1
が引数として与えられたとき、list1
の各要素 value
をキー、value
の list1
におけるインデックスをキーに対応する値とした辞書を返す関数 reverse_lookup
を作成してください。
以下のセルの ...
のところを書き換えて reverse_lookup(list1)
を作成してください。
[12]:
def reverse_lookup(list1):
...
上のセルで解答を作成した後、以下のセルを実行し、実行結果が True
になることを確認してください。
[13]:
print(reverse_lookup(['apple', 'pen', 'orange']) == {'apple': 0, 'orange': 2, 'pen': 1})
False
辞書のメソッド¶
辞書のメソッドを紹介しておきます。
キーを指定して値を得るメソッド¶
get
メソッドは、引数として指定したキーが辞書に含まれてる場合にはその値を取得し、 指定したキーが含まれていない場合には None
を返します。 get
を利用することで、エラーを回避し、登録されているかどうかわからないキーを使うことができます。 先に説明したキーを括弧、[...]
、で指定する方法では、 辞書にキーが存在しないとエラーとなりプログラムの実行が停止してしまいます。
[14]:
ppap = {'apple' : 3, 'pen' : 5}
print('キーappleに対応する値 = ', ppap.get('apple'))
print('キーorangeに対応する値 = ', ppap.get('orange'))
print('キーorangeに対応する値(エラー) = ', ppap['orange'])
キーappleに対応する値 = 3
キーorangeに対応する値 = None
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Cell In[14], line 4
2 print('キーappleに対応する値 = ', ppap.get('apple'))
3 print('キーorangeに対応する値 = ', ppap.get('orange'))
----> 4 print('キーorangeに対応する値(エラー) = ', ppap['orange'])
KeyError: 'orange'
また、get
に2番目の引数を与えると、その引数の値を「指定したキーが含まれていない場合」に get
が返す値とすることができます。
[15]:
ppap = {'apple' : 3, 'pen' : 5}
print('キーappleに対応する値 = ', ppap.get('apple', -1))
print('キーorangeに対応する値 = ', ppap.get('orange', -1))
キーappleに対応する値 = 3
キーorangeに対応する値 = -1
▲キーがない場合に登録を行う¶
setdefault
メソッドは、 指定したキーが辞書に含まれてる場合には、対応する値を返します。 キーが含まれていない場合には、2番目の引数として指定した値を返すと同時に、キーに対応する値として登録します。
[16]:
ppap = {'apple' : 3, 'pen' : 5}
print('キーappleに対応する値 = ', ppap.setdefault('apple', 7))
print('setdefault("apple", 7)を実行後の辞書 = ', ppap)
print('キーorangeに対応する値 = ', ppap.setdefault('orange', 7))
print('setdefault("orange", 7)を実行後の辞書 = ', ppap)
キーappleに対応する値 = 3
setdefault("apple", 7)を実行後の辞書 = {'apple': 3, 'pen': 5}
キーorangeに対応する値 = 7
setdefault("orange", 7)を実行後の辞書 = {'apple': 3, 'pen': 5, 'orange': 7}
上のような setdefault
を用いた手続きを、[...]
を用いて書き換えるとたとえば次のようになります。
[17]:
ppap = {'apple' : 3, 'pen' : 5}
if 'apple' not in ppap:
ppap['apple'] = 7
print('キーappleに対応する値 = ', ppap['apple'])
print('実行後の辞書 = ', ppap)
if 'orange' not in ppap:
ppap['orange'] = 7
print('キーorangeに対応する値 = ', ppap['orange'])
print('実行後の辞書 = ', ppap)
キーappleに対応する値 = 3
実行後の辞書 = {'apple': 3, 'pen': 5}
キーorangeに対応する値 = 7
実行後の辞書 = {'apple': 3, 'pen': 5, 'orange': 7}
▲キーを指定した削除¶
pop
メソッドは指定したキーおよびそれに対応する値を削除し、削除されるキーに対応付けられた値を返します。
[18]:
ppap = {'apple' : 3, 'pen' : 5}
print(ppap.pop('pen'))
print(ppap)
5
{'apple': 3}
▲全てのキーと値の削除¶
clear
メソッドは全てのキーと値を削除します。その結果、辞書は空となります。
[19]:
ppap = {'apple' : 3, 'pen' : 5}
ppap.clear()
ppap
[19]:
{}
キーの一覧を得る¶
keys
メソッドはキーの一覧を返します。これはリストのようなものとして扱うことができ、 for
ループと組み合わせて繰り返し処理で利用されます(3-2を参照してください)。 以下のように、keys
メソッドが返した結果に関数 list
を適用すると、 通常のリストになります。
[20]:
ppap = {'apple' : 3, 'pen' : 5}
list(ppap.keys())
[20]:
['apple', 'pen']
値の一覧を得る¶
values
メソッドはキーに対応する全ての値の一覧を返します。これもリストのようなものとして扱うことができます。
[21]:
list(ppap.values())
[21]:
[3, 5]
キーと値の一覧を得る¶
items
メソッドはキーとそれに対応する値をタプルにした一覧を返します。 これもタプルを要素とするリストのようなものとして扱うことができ、forループなどで活用します(3-2を参照してください)。
[22]:
list(ppap.items())
[22]:
[('apple', 3), ('pen', 5)]
▲辞書を複製する¶
copy
メソッドは辞書を複製します。リストの場合と同様に一方の辞書を変更してももう一方の辞書は影響を受けません。
[23]:
ppap = {'apple': 3, 'pen': 5, 'orange': 7}
ppap2 = ppap.copy()
ppap['banana'] = 9
print(ppap)
print(ppap2)
{'apple': 3, 'pen': 5, 'orange': 7, 'banana': 9}
{'apple': 3, 'pen': 5, 'orange': 7}
▲ keys
, values
, items
の返値¶
keys
, values
, items
メソッドの一連の説明では、返値を「リストのようなもの」と表現してきました。 通常のリストとどう違うのでしょうか?
次の例では、ppap
の keys
, values
, items
メソッドの返値をそれぞれ ks
, vs
, itms
に代入し、 print
でそれぞれの内容を表示させています。
次いで、ppap
に新たな要素を加えたのちに、同じ変数の内容を表示させています。 1, 2回目の print
で内容が異なることに注意してください。 もとの辞書が更新されると、これらの内容も動的に変わります。
[24]:
ppap = {'apple': 3, 'pen': 5, 'orange': 7}
ks = ppap.keys()
vs = ppap.values()
itms = ppap.items()
print(list(ks))
print(list(vs))
print(list(itms))
ppap['kiwi'] = 9
print(list(ks))
print(list(vs))
print(list(itms))
['apple', 'pen', 'orange']
[3, 5, 7]
[('apple', 3), ('pen', 5), ('orange', 7)]
['apple', 'pen', 'orange', 'kiwi']
[3, 5, 7, 9]
[('apple', 3), ('pen', 5), ('orange', 7), ('kiwi', 9)]
辞書とリスト¶
冒頭で述べたように、辞書では値としてあらゆる型のデータを使用できます。 すなわち、次のように値としてリストを使用する辞書を作成可能です。 リストの要素を参照するには数字インデックスをさらに指定します。
[25]:
numbers = {'dozens': [10, 20, 40], 'hundreds': [100, 101, 120, 140]}
print(numbers['dozens'])
print(numbers['dozens'][1])
[10, 20, 40]
20
逆に、辞書を要素とするリストを作成することもできます。
[26]:
ppap = {'apple': 3, 'pen': 5}
pets = {'cat': 3, 'dog': 3, 'elephant': 8}
ld = [ppap, pets]
print(ld[1])
print(ld[1]['dog'])
{'cat': 3, 'dog': 3, 'elephant': 8}
3
練習¶
辞書 dic1
と文字列 str1
が引数として与えられたとき、 以下のように dic1
を変更する関数 handle_collision
を作成してください。 ただし、dic1
のキーは整数、キーに対応する値は文字列を要素とするリストとします。
dic1
にstr1
の長さn
がキーとして登録されていない場合、str1
のみを要素とするリストls
を作成し、dic1
にキーn
、n
に対応する値ls
を登録します。dic1
にstr1
の長さn
がキーとして登録されている場合、そのキーに対応する値(リスト)にstr1
を追加します。
以下のセルの ...
のところを書き換えて handle_collision(dic1, str1)
を作成してください。
[27]:
def handle_collision(dic1, str1):
...
上のセルで解答を作成した後、以下のセルを実行し、実行結果が True
になることを確認してください。
[28]:
dic1_orig = {3: ['ham', 'egg'], 6: ['coffee', 'brandy'], 9: ['port wine'], 15: ['curried chicken']}
dic1_result = {3: ['ham', 'egg', 'tea'], 6: ['coffee', 'brandy'], 9: ['port wine'], 15: ['curried chicken']}
handle_collision(dic1_orig, 'tea')
print(dic1_orig == dic1_result)
False
練習の解答¶
[29]:
def reverse_lookup(list1):
dic1 = {} # 空の辞書を作成する
for value in list1:
dic1[value] = list1.index(value)
return dic1
#reverse_lookup(['apple', 'pen', 'orange'])
[30]:
def handle_collision(dic1, str1):
if dic1.get(len(str1)) is None:
ls = [str1]
else:
ls = dic1[len(str1)]
ls.append(str1)
dic1[len(str1)] = ls
#handle_collision({3: ['ham', 'egg'], 6: ['coffee', 'brandy'], 9: ['port wine'], 15: ['curried chicken']}, 'tea')
[ ]: