※当サイトの記事には、広告・プロモーションが含まれます。

Pythonの辞書型 (dictionary) を2次元で空で初期化したい

natgeo.nikkeibp.co.jp

 首都直下地震南海トラフ巨大地震では、関東大震災時の出火件数より多くなる可能性があります。つまり、火気使用環境の変化や転倒防止対策などの普及によって、出火率自体は減っても出火件数自体はむしろ増えるかもしれない。出火という変数で考えると関東大震災当時よりもむしろ状況は悪くなっていると考えた方がよいかもしれません。

【解説】「いまだに高い地震火災リスク」、関東大震災から100年 | ナショナル ジオグラフィック日本版サイト

⇧ 鎮火できずに延焼し続けた場合、非難する場所が残るのか心配ですな...

「首都直下地震」や「南海トラフ巨大地震」が与える影響が予測できなので何とも言えませんが、消防活動が正常に機能するのかが疑問ではありますな...

ちなみに、過去に起きた「関東大震災」は、

防災の日(ぼうさいのひ)は、「政府、地方公共団体等関係諸機関をはじめ、広く国民が台風高潮津波地震等の災害についての認識を深め、これに対処する心構えを準備する」ために制定された防災啓発デー。日付は9月1日

防災の日 - Wikipedia

概要

防災の日」は、1960年昭和35年)に、内閣閣議了解により制定された。9月1日の日付は、1923年大正12年)9月1日に発生した関東大震災にちなんだものである。また、例年8月31日 - 9月1日付近は、台風の襲来が多いとされる二百十日にあたり、「災害への備えを怠らないように」との戒めも込められている。

防災の日 - Wikipedia

⇧「防災の日」が制定される要因の1つになっているようです。

とりあえず、怪我せず動ける体力は維持しておかないとですかね...

ちなみに、

nazology.kusuguru.co.jp

専門家によると、人が水なしで生きていける期間はわずか3~7日とのことです。

しかもこれは一般的な気温や湿度の下での話であって、砂漠のような暑い場所であれば、その日数はさらに短くなります。

また、子どもや乳幼児ではもっと短い期間しか耐えられないでしょう。

人が「飲まず食わず」で生き延びられる限界とは? - ナゾロジー

専門家は、食べ物なしで成人が耐えられる限界は平均して3週間ほどと考えています。

人が「飲まず食わず」で生き延びられる限界とは? - ナゾロジー

実際、1997年に発表された研究(Michael Peel,BMJ(1997))では、ハンガーストライキで自発的に食事を止めた人は、平均して45〜61日後に死亡していると報告されています。

人が「飲まず食わず」で生き延びられる限界とは? - ナゾロジー

⇧ という説があり、防災として、最低限「水」だけでも備蓄しておかないと被災後に生き延びるのが難しそう...

後は、

www.meti.go.jp

トイレ備蓄忘れていませんか?
災害時には断水や下水配管の損傷によりご家庭のトイレ(水洗トイレ)が使えなくなることがあります。
もしもの時に備えて携帯トイレ、簡易トイレといった災害時用トイレを備蓄しましょう。

https://www.meti.go.jp/policy/mono_info_service/mono/jyutaku/toirebichiku.html

⇧「排泄」に対する備えとかも必要ですと。

防災の備えをせねばですね。

Pythonの辞書型 (dictionary) を2次元で空で初期化したい

JavaでいうところのMapのような構造のデータを、Pythonで実現するとなると「辞書型 (dictionary)」を利用することになるとは思うのですが、2次元で宣言し空で初期化する方法が分からなかったので、調べてみました。

ネットの情報によりますと、

stackoverflow.com

qiita.com

⇧ 上記サイト様にありますように、

from collections import defaultdict
two_dimention_dict = defaultdict(dict)

⇧ で実現できるっぽい。

3次元は、

stackoverflow.com

⇧ lambdaを利用する形になるっぽい。

で、3次元より上になってくると、

stackoverflow.com

再帰処理とかで対応する感じになるっぽい。

流石に、4次元からは、再帰処理を利用しないと実現できないってのは、予測できないのだが...

Javaだと、

qiita.com

stackoverflow.com

stackoverflow.com

⇧ 上記サイト様によりますと、単純に型を入れ子にしていけば良さそう。

次元が増えていけば、型の入れ子が深くなっていくイメージでしょうか。

実際に動作検証していないので、何とも言えませんが、Pythonのように次元が異なると異なる実装方法になるということは無さそう。

Pythonの辞書型 (dictionary)を2次元、3次元、4次元で、それぞれ空で初期化してみる

というわけで、試してみる。

■C:\Users\Toshinobu\Desktop\soft_work\python_work\fastapi\app\src\test\py\test_experimental.py

from collections import defaultdict
import pytest

# import asyncio

from pprint import pprint


class TestExperimental:

    # 2次元の辞書型 (dictionary)のテスト
    def test_01(self):
        # テストデータ
        students_exam = {
            "taro": {"math": 70, "japanese": 80, "science": 40},
            "hanako": {"math": 50, "science": 90, "english": 50},
            "john": {"english": 90, "music": 70, "japanese": 50},
            "mika": {"social": 50, "math": 60, "science": 90},
        }

        # 辞書型 (dictionary)の変数を宣言、2次元で初期化
        # 要素は空
        two_dimention_dict = defaultdict(dict)

        print("[要素追加前][two_dimention_dict]")
        pprint(two_dimention_dict)
        # 2次元の辞書型 (dictionary)の変数に要素を追加
        for key, values in students_exam.items():
            for subject, score in values.items():
                two_dimention_dict[key][subject] = score

        print("[要素追加後][two_dimention_dict]")
        pprint(two_dimention_dict)

    # 3次元の辞書型 (dictionary)のテスト
    def test_02(self):
        # テストデータ
        students_exam = {
            "taro": {"math": 70, "japanese": 80, "science": 40},
            "hanako": {"math": 50, "science": 90, "english": 50},
            "john": {"english": 90, "music": 70, "japanese": 50},
            "mika": {"social": 50, "math": 60, "science": 90},
        }

        # 辞書型 (dictionary)の変数を宣言、3次元で初期化
        # 要素は空
        three_dimention_dict = defaultdict(lambda: defaultdict(dict))

        print("[要素追加前][three_dimention_dict]")
        pprint(three_dimention_dict)
        # 3次元の辞書型 (dictionary)の変数に要素を追加
        no: int = 1
        for key, values in students_exam.items():
            for subject, score in values.items():
                three_dimention_dict[no][key][subject] = score
            no += 1

        print("[要素追加後][three_dimention_dict]")
        pprint(three_dimention_dict)

    # 4次元の辞書型 (dictionary)のテスト
    def test_03(self):
        # テストデータ
        students_exam = {
            "taro": {"math": 100, "japanese": 100, "science": 100},
            "hanako": {"math": 50, "science": 90, "english": 50},
            "john": {"english": 90, "music": 80, "japanese": 80},
            "mika": {"social": 70, "math": 60, "science": 90},
        }

        rank_list = ["S", "C", "A", "B"]

        # 辞書型 (dictionary)の変数を宣言、4次元で初期化
        # 要素は空
        forth_dimention_dict = TestExperimental.nested_dict(4, dict)

        print("[要素追加前][forth_dimention_dict]")
        pprint(forth_dimention_dict)
        # 4次元の辞書型 (dictionary)の変数に要素を追加
        no: int = 1
        for key, values in students_exam.items():
            for subject, score in values.items():
                forth_dimention_dict[no][rank_list[no - 1]][key][subject] = score
            no += 1

        print("[要素追加後][forth_dimention_dict]")
        pprint(forth_dimention_dict)

    ################################################################
    # メソッド
    # 4次元以上の辞書型 (dictionary)の変数を空で初期化する
    ################################################################
    @staticmethod
    def nested_dict(n, type):
        """
        param n 次元
        param type データ型
        """
        if n == 1:
            return defaultdict(type)
        else:
            return defaultdict(lambda: TestExperimental.nested_dict(n - 1, type))

⇧ で保存。実行すると、

以下のような結果がコンソールに出力される。

Received JSON data in run script
Running pytest with args: ['-p', 'vscode_pytest', '--cov=.', '--cov-report', 'xml', '--capture=no', '--rootdir=c:\\Users\\Toshinobu\\Desktop\\soft_work\\python_work\\fastapi', 'c:\\Users\\Toshinobu\\Desktop\\soft_work\\python_work\\fastapi\\app\\src\\test\\py\\test_experimental.py::TestExperimental::test_01', 'c:\\Users\\Toshinobu\\Desktop\\soft_work\\python_work\\fastapi\\app\\src\\test\\py\\test_experimental.py::TestExperimental::test_02', 'c:\\Users\\Toshinobu\\Desktop\\soft_work\\python_work\\fastapi\\app\\src\\test\\py\\test_experimental.py::TestExperimental::test_03']
============================= test session starts =============================
platform win32 -- Python 3.12.4, pytest-8.3.2, pluggy-1.5.0
rootdir: c:\Users\Toshinobu\Desktop\soft_work\python_work\fastapi
plugins: anyio-4.4.0, asyncio-0.23.8, cov-5.0.0
asyncio: mode=Mode.STRICT
collected 3 items

app\src\test\py\test_experimental.py [要素追加前][two_dimention_dict]
defaultdict(<class 'dict'>, {})
[要素追加後][two_dimention_dict]
defaultdict(<class 'dict'>,
            {'hanako': {'english': 50, 'math': 50, 'science': 90},
             'john': {'english': 90, 'japanese': 50, 'music': 70},
             'mika': {'math': 60, 'science': 90, 'social': 50},
             'taro': {'japanese': 80, 'math': 70, 'science': 40}})
.[要素追加前][three_dimention_dict]
defaultdict(<function TestExperimental.test_02.<locals>.<lambda> at 0x00000252693F11C0>, {})
[要素追加後][three_dimention_dict]
defaultdict(<function TestExperimental.test_02.<locals>.<lambda> at 0x00000252693F11C0>,
            {1: defaultdict(<class 'dict'>,
                            {'taro': {'japanese': 80,
                                      'math': 70,
                                      'science': 40}}),
             2: defaultdict(<class 'dict'>,
                            {'hanako': {'english': 50,
                                        'math': 50,
                                        'science': 90}}),
             3: defaultdict(<class 'dict'>,
                            {'john': {'english': 90,
                                      'japanese': 50,
                                      'music': 70}}),
             4: defaultdict(<class 'dict'>,
                            {'mika': {'math': 60,
                                      'science': 90,
                                      'social': 50}})})
.[要素追加前][forth_dimention_dict]
defaultdict(<function TestExperimental.nested_dict.<locals>.<lambda> at 0x00000252693F1440>, {})
[要素追加後][forth_dimention_dict]
defaultdict(<function TestExperimental.nested_dict.<locals>.<lambda> at 0x00000252693F1440>,
            {1: defaultdict(<function TestExperimental.nested_dict.<locals>.<lambda> at 0x00000252693F1300>,
                            {'S': defaultdict(<function TestExperimental.nested_dict.<locals>.<lambda> at 0x00000252693F14E0>,
                                              {'taro': defaultdict(<class 'dict'>,
                                                                   {'japanese': 100,
                                                                    'math': 100,
                                                                    'science': 100})})}),
             2: defaultdict(<function TestExperimental.nested_dict.<locals>.<lambda> at 0x00000252693F1580>,
                            {'C': defaultdict(<function TestExperimental.nested_dict.<locals>.<lambda> at 0x00000252693F1620>,
                                              {'hanako': defaultdict(<class 'dict'>,
                                                                     {'english': 50,
                                                                      'math': 50,
                                                                      'science': 90})})}),
             3: defaultdict(<function TestExperimental.nested_dict.<locals>.<lambda> at 0x00000252693F16C0>,
                            {'A': defaultdict(<function TestExperimental.nested_dict.<locals>.<lambda> at 0x00000252693F1760>,
                                              {'john': defaultdict(<class 'dict'>,
                                                                   {'english': 90,
                                                                    'japanese': 80,
                                                                    'music': 80})})}),
             4: defaultdict(<function TestExperimental.nested_dict.<locals>.<lambda> at 0x00000252693F1800>,
                            {'B': defaultdict(<function TestExperimental.nested_dict.<locals>.<lambda> at 0x00000252693F18A0>,
                                              {'mika': defaultdict(<class 'dict'>,
                                                                   {'math': 60,
                                                                    'science': 90,
                                                                    'social': 70})})})})
.

---------- coverage: platform win32, python 3.12.4-final-0 -----------
Coverage XML written to file coverage.xml


============================== 3 passed in 0.32s ==============================
Finished running tests!

⇧ う~む、上手く実現できているのか分かり辛い...

変数に型を付けることができたら良かったんですが、2次元以上の辞書型 (dictionary)の変数の型がどうなるか分からないんよね...

ちなみに、

qiita.com

zenn.dev

⇧ 上記サイト様によりますと、「namedtuple」という型も存在するそうな。

Python の公式のドキュメントによると、「コンテナデータ型」に属する型の1つらしい。

docs.python.org

このモジュールは、汎用の Python 組み込みコンテナ dictlistset, および tuple に代わる、特殊なコンテナデータ型を実装しています。

https://docs.python.org/ja/3.8/library/collections.html

⇧ 他にも、いろいろあって、使い分けがよく分からん...

それにしても、Pythonの辞書型 (dictionary)で、2次元以上で空で初期化することって、実業務では無い感じなんですかね?

ネット上の情報のほとんどが、海外のものだったので、日本では利用する機会が無いということなんですかね?

Python、枯れた技術なはずなのに、情報が欠しいんですよね...

毎度モヤモヤ感が半端ない…

今回はこのへんで。