辞書内包表記を使って、辞書を作成する方法と、zip関数と辞書内包表記を組み合わせる方法、注意点などを紹介する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
# 辞書内包表記の基本型
d = {k: k ** 2 for k in range(5)}
print(d) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 辞書内包表記とzip関数との組み合わせ
articles = [
'リストの内包表記と「if」を組み合わせるには',
'内包表記でリストを作成するには',
'バイナリファイルの読み書きまとめ',
'テキストファイルの読み書きまとめ'
]
urls = [
'https://www.atmarkit.co.jp/ait/articles/2107/06/news020.html',
'https://www.atmarkit.co.jp/ait/articles/2106/29/news021.html',
'https://www.atmarkit.co.jp/ait/articles/2106/22/news022.html',
'https://www.atmarkit.co.jp/ait/articles/2106/15/news016.html'
]
d = {title: url for title, url in zip(articles, urls)}
for title, url in d.items():
print(f'{title}: {url[-20:]}')
# 出力結果:
#リストの内包表記と「if」を組み合わせるには: 2107/06/news020.html
#内包表記でリストを作成するには: 2106/29/news021.html
#バイナリファイルの読み書きまとめ: 2106/22/news022.html
#テキストファイルの読み書きまとめ: 2106/15/news016.html
# 同じことはdict関数でもできる
d = dict(zip(articles, urls))
for title, url in d.items():
print(f'{title}: {url[-20:]}') # 出力結果は上に同じ
# 反復可能オブジェクトから得た値を加工するには内包表記を使う
d = {t: u[-20:] for t, u in zip(articles, urls) if '内包表記' in t}
for title, url in d.items():
print(f'{title}: {url}')
# 出力結果:
#リストの内包表記と「if」を組み合わせるには: 2107/06/news020.html
#内包表記でリストを作成するには: 2106/29/news021.html
内包表記は辞書の作成にも使える。以下にその基本構文を示す。
d = {キー: 値 for キー/値の計算で使用する変数 in 反復可能オブジェクト}
辞書内包表記ではリスト内包表記とは異なり、外側を波かっこ「{}」で囲む。また、その中に新しく作成する辞書の要素を「キー: 値」として書く。辞書の要素(キーと値)を計算する際には、上の構文に示した「キー/値の計算で使用する変数」に「反復可能オブジェクト」から要素が1つずつ渡されるので、その値を使って「キー」または「値」を計算する。
以下にシンプルな例を示す。
d = {k: k ** 2 for k in range(5)}
print(d) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
この例では、rangeオブジェクトから変数kに整数値が順次渡され、その値を使って、辞書のキー(kの値と同値)とその値(kの値を二乗したもの)を計算している。
内包表記とzip関数を組み合わせることで、2つのリストの一方をキーに、もう一方をその値とする辞書を作成することも可能だ。以下に例を示す。
articles = [
'リストの内包表記と「if」を組み合わせるには',
'内包表記でリストを作成するには',
'バイナリファイルの読み書きまとめ',
'テキストファイルの読み書きまとめ'
]
urls = [
'https://www.atmarkit.co.jp/ait/articles/2107/06/news020.html',
'https://www.atmarkit.co.jp/ait/articles/2106/29/news021.html',
'https://www.atmarkit.co.jp/ait/articles/2106/22/news022.html',
'https://www.atmarkit.co.jp/ait/articles/2106/15/news016.html'
]
d = {title: url for title, url in zip(articles, urls)}
for title, url in d.items():
print(f'{title}: {url[-20:]}')
# 出力結果:
#リストの内包表記と「if」を組み合わせるには: 2107/06/news020.html
#内包表記でリストを作成するには: 2106/29/news021.html
#バイナリファイルの読み書きまとめ: 2106/22/news022.html
#テキストファイルの読み書きまとめ: 2106/15/news016.html
articlesは本連載の記事タイトルを要素とするリストで、urlsは各記事のURLを要素とするリストとなっている。上に示した内包表記「{title: url for title, url in zip(articles, urls)}」は、zip関数でこれらのリストをまとめて、そこから「記事タイトル: URL」という組を要素とする辞書を作成している。
ただし、これだけであれば、dict関数を使うとよりシンプルに書ける。
d = dict(zip(articles, urls))
for title, url in d.items():
print(f'{title}: {url[-20:]}')
dict関数は「2つの要素からなる反復可能オブジェクトを要素とする反復可能オブジェクト」を受け取れる。例えば、「[['k1', 'v1'], ['k2', 'v2']]」のようなリストがそうだ。この場合、dict関数は外側のリストの要素(['k1', 'v1'])の先頭要素をキーとして、次の要素を値として、辞書を作成する。つまり、今の例であれば、{'k1': 'v1', 'k2': 'v2'}という辞書を作成する。
sample_list = [['k1', 'v1'], ['k2', 'v2']]
d2 = dict(sample_list)
print(d2) # {'k1': 'v1', 'k2': 'v2'}
zip関数の戻り値は、引数に受け取った反復可能オブジェクトと同一インデックス位置にある要素を組としたタプルを返すイテレータであり、これをdict関数に渡すと、辞書内包表記でzip関数を使った場合と同じことができるということだ。
では、常にdict関数を使えばよいかというと、そうでもない。元の反復可能オブジェクトの値を加工したり、フィルタリングしたりするには内包表記を使うことになるだろう。以下に例を示す(コードが1行に収まるようにループ変数の名前を1文字としている)。
d = {t: u[-20:] for t, u in zip(articles, urls) if '内包表記' in t}
for title, url in d.items():
print(f'{title}: {url}')
# 出力結果:
#リストの内包表記と「if」を組み合わせるには: 2107/06/news020.html
#内包表記でリストを作成するには: 2106/29/news021.html
この例では、内包表記のif句を利用して、記事リスト(articles)の要素の中で「内包表記」という語が含まれているものだけをキーとするようにフィルタリングを行い、その値のURLについては「url[-20:]」のようにして4桁の整数値以降だけを抽出するように元のリストの要素を加工している。なお、if句については「リストの内包表記と「if」を組み合わせるには」も参照されたい。
最後に注意点だが、辞書のキーにできるのはハッシュ可能なオブジェクトのみであることは覚えておこう。リストや辞書のようにその内容が変更可能なオブジェクトは、ハッシュ可能なオブジェクトではなく、キーとすることはできない。
klist = [[1, 2], [3, 4]]
vlist = [['foo', 'bar'], ['bar', 'baz']]
d = {k: v for k, v in zip(klist, vlist)} # TypeError: unhashable type: 'list'
また、タプルのようなイミュータブル(変更不可能)なオブジェクトであっても、その要素がミュータブル(変更可能)な場合がある。それらのオブジェクトはハッシュ可能ではないので、やはりキーにはできない。
ktuple1 = ((1, 'foo'), (3, 'bar')) # 変更可能な要素は含まれていない
ktuple2 = ((1, ['foo', 'bar']), (2, ['bar', 'baz'])) # 変更可能な要素を含む
vlist = [['foo', 'bar'], ['bar', 'baz']] # 値は変更可能でも構わない
d = {k: v for k, v in zip(ktuple1, vlist)}
print(d) # {(1, 'foo'): ['foo', 'bar'], (3, 'bar'): ['bar', 'baz']}
d = {k: v for k, v in zip(ktuple2, vlist)} # TypeError: unhashable type: 'list'
Copyright© Digital Advantage Corp. All Rights Reserved.