[Python入門] dict型


## 想定読者

+ Python勉強したて。型について知りたい
+ Pythonのdict型について知りたい
+ 理解の助けになる実装例を知りたい
+ int, float, str, list型について知っている

## 目的

+ dict型についてわかる
+ 利用用途が分かる

## dictとは

+ [公式リファレンス](https://docs.python.org/ja/3/c-api/dict.html)
+ かなりよく使うデータ型
+ 値を入れておく箱。listとの違いは、keyと呼ばれる索引がついていること。
+ 他のプログラミング言語で同様のデータ構造の例
    + Java: Map
    + Ruby: Hash
    + JavaScript: object
    + PHP: array
    + 備考
        + 言語によっては連想配列と呼ばれ、配列の一種として扱われていることもある

## dictを使うメリット

+ 物を数えたり、集めたりする時に使いやすい
+ dictはlistと同様に値を入れておく箱として扱えるが、dictでは文字列を使って値を出し入れできるため、コードが読みやすくなる

## dict構造まわりの用語

+ key(キー)
    + dict型にバリューを出し入れするときの値
    + hash化可能である必要がある（例えば、int, float, str, tuple型はhash化可能だが、list, dict型はhash化できない)
    + 同じdictオブジェクトの中で、**キーは重複してはいけない**
        + あえてそういう制限をつけることで、便利になることがある。
+ value(バリュー)
    + dict型に格納する物
    + 変数に入れられるオブジェクトはなんでも入る
+ hash(ハッシュ)
    + hash化: オブジェクトに何かしらの関数を適用して、オブジェクトを数値に変換する処理
    + hash値: hash化によって変換された数値のこと
    + シリアライズ: hash化と似た処理で、オブジェクトをファイルに書き出し可能な状態にする処理
    + ハッシュテーブル
        + dict型は基本的にハッシュテーブルの考え方を使って実装されているものが多いと思う
        + ハッシュテーブルについて知ることでdict型の理解も深まるため、調べてみると良いと思う
    + 備考
        + エラーを読む時にたまに出てくる（下の例は、list型はhash化できないから、そんなdictオブジェクトを作れないよというエラー)

            ```python
            >>> {[1]: '何かしらの値'}                                                                                                       
            Traceback (most recent call last):                                                                                     
              File "<stdin>", line 1, in <module>                                                                                  
            TypeError: unhashable type: 'list'  
            ```

## dictの文法

```
{
    'id': 'id-1',
    'name': '鈴木',
    'email': 'aaaaa@example.com',
}
```

+ dictオブジェクトは`{}`で囲む
+ `key: value`を`,`(カンマ)区切りで書く
    + 最後のカンマはあってもエラーにならない

## dictへのバリューの出し入れ

```python
user = {
    'id': 'id-1',
    'name': '鈴木',
    'email': 'aaaaa@example.com',
}
print(user['name'])          # -> 鈴木
user['name'] = '田中' # nameというキーに対するバリューを'田中'に置き換えます
print(user['name'])          # -> 田中にバリューを書き換えることができました
```

## 応用例1

dictのバリューにはdictなどを入れることができます。
また、listの値にもdictを入れることができます。

```python
user_list = [
    {
        'id': 'id-1',
        'name': {'first_name': '鈴木', 'last_name': '一郎'},
        'email': 'aaaaa@example.com',
        'hobbies': [
            'サイクリング',
            '旅行',
        ],
    },
    {
        'id': 'id-2',
        'name': {'first_name': '佐藤', 'last_name': '次郎'},
        'email': 'aaaaa@example.com',
        'hobbies': [
            'サイクリング',
            '写真',
        ],
    },
]
```

+ 備考
    これを全てlistで表現しようとすると、初見では理解しづらいコードになってしまいます。

    ```python
    user_list = [
        [
            'id-1'
            ['鈴木', '一郎'],
            'aaaaa@example.com',
            [
                'サイクリング',
                '旅行',
            ],
        ],
        [
            'id-2',
            ['佐藤', '次郎'],
            'aaaaa@example.com',
            [
                'サイクリング',
                '写真',
            ],
        ],
    ]
    ```

    上記の例では、予めユーザーの2番目の要素が苗字と名前であるという知識がないと読みづらいです。
    文字列をキーにすることで、バリューの意味を表現しやすくなります

## 応用例2

dictは集計によく用いられます。
例えば、応用例1のuser_listの中に現れるhobby(趣味)の頻度を知りたい場合は、下記のようにしてdictを使って集計することができます


```python
user_list = [
    {
        'id': 'id-1',
        'name': {'first_name': '鈴木', 'last_name': '一郎'},
        'email': 'aaaaa@example.com',
        'hobbies': [
            'サイクリング',
            '旅行',
        ],
    },
    {
        'id': 'id-2',
        'name': {'first_name': '佐藤', 'last_name': '次郎'},
        'email': 'aaaaa@example.com',
        'hobbies': [
            'サイクリング',
            '写真',
        ],
    },
]

hobby_dict = {}  # 新たに集計用のdictオブジェクトを作る

# ユーザーリストからlistの要素であるdictオブジェクトをforループで取り出して、userという変数にセット
for user in user_list:
    # 'hobbies'というキーのバリューから'サイクリング', '旅行'などの文字列をforループで取り出して、hobbyという変数にセット
    for hobby in user['hobbies']:

        # hobby_dictにキーが入っていなければ、バリューを0で初期化する
        if hobby not in hobby_dict:
            hobby_dict[hobby] = 0

        # 前のバリューに1を加算した値で、同じキーのバリューを更新
        hobby_dict[hobby] = hobby_dict[hobby] + 1

# 集約の結果を確認する
print(hobby_dict['サイクリング'])  # -> 2
print(hobby_dict['旅行'])          # -> 1
```

## まとめ

以上、dictについてとその応用例について説明しました。
他の言語でも一般的に使われているデータ構造なので、他の人のコードを読んでいると必ずと言って良いほど出てくるので、必ず覚えましょう！

より詳しい文法やdictのメリットを知りたい場合は、下記のキーワードを使って調べてみると面白いと思います！

+ collections defaultdict
+ dict内包表記
+ スプレッド構文
+ dict 計算量