collections

【Python】defaultdictで規定値を持つ辞書を定義する(collections.defaultdict)

【Python】defaultdictで規定値を持つ辞書を定義する(collections.defaultdict)
naoki-hn

Python で規定値を持つ辞書を定義する collections モジュールの defaultdict について解説します。

defaultdictcollections モジュール)

Python 標準の辞書(dict)では、辞書にないキーの値を操作しようとするとエラーになるため、初期化を意識する必要があります。この時、collections モジュールの defaultdict を使用することで規定値を持つ辞書を扱うことができます。

この記事では、規定値を持つ辞書を定義する collections モジュールの defaultdict について基本的な使い方を紹介します。

リスト要素の出現回数カウント

まずは、Python 標準の辞書(dict)を用いてリストに含まれている値の出現数をカウントするプログラムを考えてみます。リストに含まれる値を辞書の key として、カウントを 1 ずつインクリメントしていきます。

例えば、以下のようにプログラムを書いたとします。

data = ["A", "B", "A", "C", "D", "B", "A", "B", "D"]
dict_count = {}

for key in data:
    dict_count[key] += 1

print(dict_count)
【実行結果例】
Traceback (most recent call last):
...(省略)...
KeyError: 'A'

上記プログラムで、"A" は最初は辞書内にないために KeyError が発生します。解決方法として、初期化として値 1 を入れるように設定する方法が使えます。

data = ["A", "B", "A", "C", "D", "B", "A", "B", "D"]
dict_count = {}

for key in data:
    if key in dict_count:
        dict_count[key] += 1
    else:
        dict_count[key] = 1

print(dict_count)
【実行結果】
{'A': 3, 'B': 3, 'C': 1, 'D': 2}

このように対応することが可能ですが、if...else... により少しコードが長くなってしまいます。辞書にないキーの場合は、デフォルトで値に 0 が入るようにできれば、回数をインクリメントする「dict_count[key] += 1」のコードのみでよくなります。

このようなときに簡単に対応できるよう、規定値を持つ辞書を定義できるのが collections モジュールの defaultdict です。

collections.defaultdict の定義と使い方

上記で紹介したリスト要素の出現回数をカウントするプログラムを用いて collections モジュールの defaultdict を使い方を紹介します。

int0 で初期化する場合

キーが存在しない場合に値を 0 で規定値として初期化したい場合には、以下のように defaultdict の引数に「int」クラスを指定して使用します。

import collections

data = ["A", "B", "A", "C", "D", "B", "A", "B", "D"]
dict_count = collections.defaultdict(int)

for key in data:
    dict_count[key] += 1

print(dict_count)
【実行結果】
defaultdict(<class 'int'>, {'A': 3, 'B': 3, 'C': 1, 'D': 2})

defaultdict を使用するためには collections モジュールをインポートする必要があります。結果を見るとデフォルトで 0 が設定されるため、リスト要素の出現回数をカウントできていることが分かります。

lambda 関数での表現

上記例では、int クラスを指定しましたが lamda 関数を使用して以下のように記載しても結果は同じになります。

import collections

data = ["A", "B", "A", "C", "D", "B", "A", "B", "D"]
# lambda関数で記載
dict_count = collections.defaultdict(lambda: int())

for key in data:
    dict_count[key] += 1

print(dict_count)
【実行結果】
defaultdict(<function <lambda> at 0x0000028AC65D6310>, {'A': 3, 'B': 3, 'C': 1, 'D': 2})

上記は int() を返却値とする lambda 関数を defaultdict に渡しています。「int()」は print してみると分かりますが 0 になるので、0 で初期化されることになります。結果は同じですが、defaultdictprint してみると先ほどは <class 'int'> となっていたものが function<lambda> となっている点で異なります。

lambda 関数に関しては「ラムダ(lambda)関数:無名関数の使い方」を参考にしてください。

float0.0 で初期化する場合

float0.0 で規定値を設定する場合も int の時と同様ですが見てみましょう。

import collections

data = ["A", "B", "A", "C", "D", "B", "A", "B", "D"]
dict_count = collections.defaultdict(float)

for key in data:
    dict_count[key] += 1.0

print(dict_count)
【実行結果】
defaultdict(<class 'float'>, {'A': 3.0, 'B': 3.0, 'C': 1.0, 'D': 2.0})

上記を見るとデフォルトで 0.0 が設定されて、1.0 ずつインクリメントできていることが分かります。

lambda 関数での表現

上記例では、float クラスを指定しましたが lamda 関数を使用して以下のように記載しても結果は同じになります。

import collections

data = ["A", "B", "A", "C", "D", "B", "A", "B", "D"]
# lambdaで記載
dict_count = collections.defaultdict(lambda: float())

for key in data:
    dict_count[key] += 1.0

print(dict_count)
【実行結果】
defaultdict(<function <lambda> at 0x000001AA0507A050>, {'A': 3.0, 'B': 3.0, 'C': 1.0, 'D': 2.0})

結果は同じですが、クラスが関数に変わるという点については int() で説明した例と同様になります。

list 等でも同様に対応可能

上記では例として 0 で規定値を設定する int と、0.0 で規定値を設定する float の例を紹介しましたが、以下のような他のクラスも同様に使用可能です。

クラス規定値
int0
float0.0
list[]
dict{}
boolFalse

関数で任意の規定値を定義する

lambda 関数のことが理解できると intfloat の例が「dict_count = collections.defaultdict(lambda: 0)」や「dict_count = collections.defaultdict(lambda: 0.0)」としても同じことが分かると思います。

つまり、defaultdict の引数には、規定値が返却値となる関数を指定することができます。もし、複雑な関数が必要な場合は lambda 関数ではなく、通常の def で定義した上で引数に渡すことも可能です。

例えば、以下のように def で定義した関数を渡すことも可能です。

import collections


def init_dict():
    # 本来複雑な処理を書けるが例として1を返却するのみ
    return 1


data = ["A", "B", "A", "C", "D", "B", "A", "B", "D"]
dict_count = collections.defaultdict(init_dict)

for key in data:
    dict_count[key] += 1

print(dict_count)
【実行結果】
defaultdict(<function init_dict at 0x000001294089A170>, {'A': 4, 'B': 4, 'C': 2, 'D': 3})

この時、関数自体を渡すので () をつけずに「init_dict」を渡すことに注意しましょう。なお、上記は例として非常に簡単な 1 を返す関数にしましたが、より複雑な条件の初期化処理を書いてももちろん構いません。

defaultdictdict のサブクラス

上記で紹介してきた defaultdict は、dict のサブクラスとなっているため、dictと同じように各種メソッドを使って扱うことができます。

まとめ

Pythonで規定値を持つ辞書を定義する collections モジュールの defaultdict について解説しました。

リストの要素数カウント例で defaultdict の基本を説明しました。defaultdict は、dict のサブクラスであるため dict と同様に各種メソッドが使用できます。

また、defaultdict の引数には、規定値が返却値となる関数を指定することができますので状況によりうまく使いこなしてください。

defaultdict の公式ドキュメントはこちらを参照してください。

ソースコード

上記で紹介しているソースコードについては GitHub にて公開しています。参考にしていただければと思います。

あわせて読みたい
【Python Tech】プログラミングガイド
【Python Tech】プログラミングガイド

ABOUT ME
ホッシー
ホッシー
システムエンジニア
はじめまして。当サイトをご覧いただきありがとうございます。 私は製造業のメーカーで、DX推進や業務システムの設計・開発・導入を担当しているシステムエンジニアです。これまでに転職も経験しており、以前は大手電機メーカーでシステム開発に携わっていました。

プログラミング言語はこれまでC、C++、JAVA等を扱ってきましたが、最近では特に機械学習等の分析でも注目されているPythonについてとても興味をもって取り組んでいます。これまでの経験をもとに、Pythonに興味を持つ方のお役に立てるような情報を発信していきたいと思います。どうぞよろしくお願いいたします。

※キャラクターデザイン:ゼイルン様
記事URLをコピーしました