2
2

More than 3 years have passed since last update.

dict in dict な dict を dict にする

Last updated at Posted at 2020-03-30

表題の件に付きまして、python初心者が実装しましたので報告いたします。
そもそも、dict in dict な dict とは、以下のようなdictのことです。

{'name': '2M2VgARX', 'js': {'a': 0, 'b': 0, 'c': 'sdmo'}}

in しているdictのキーとin されているdictのキーは、合わせても一意なので、一つの辞書にまとめたいなーと思い、そんな関数を作ってみました。

変換後イメージ

{'name': '2M2VgARX', 'js_a': 0, 'js_b': 0, 'js_c': 'sdmo'}

標準関数がありそうですが、自分の検索能力が低いため、
見つからなかったことはご了承下さい。

実装

import secrets
import string


def dict_extract(item, prefix=''):
    return_dict = {}
    for key, value in item.items():
        if isinstance(value, dict):
            prefix += f'{key}_'
            return_dict.update(dict_extract(value, prefix))
        else:
            return_dict[prefix + key] = value
    return return_dict


def main():
    # create sample data
    items =[]
    alphabet = string.ascii_letters + string.digits
    password = ''.join(secrets.choice(alphabet) for i in range(8))
    for i in range(10):
        password = ''.join(secrets.choice(alphabet) for i in range(8))
        tmp = {'a': i, 'b': i*2, 'c': 'sdmo'}
        tmp_item = {'name': password, 'js': tmp}
        items.append(tmp_item)

    # print dict
    for item in items:
        print(dict_extract(item))


if __name__ == "__main__":
    main()

実行結果

{'name': 'ZQ4NaBbc', 'js_a': 0, 'js_b': 0, 'js_c': 'sdmo'}
{'name': 'E5hS6IqS', 'js_a': 1, 'js_b': 2, 'js_c': 'sdmo'}
{'name': 'PC1xzQGi', 'js_a': 2, 'js_b': 4, 'js_c': 'sdmo'}
{'name': 'McJTGCjl', 'js_a': 3, 'js_b': 6, 'js_c': 'sdmo'}
{'name': '3hYsdwB8', 'js_a': 4, 'js_b': 8, 'js_c': 'sdmo'}
{'name': 'UKocBVhJ', 'js_a': 5, 'js_b': 10, 'js_c': 'sdmo'}
{'name': '3QVlhwOn', 'js_a': 6, 'js_b': 12, 'js_c': 'sdmo'}
{'name': 'bspVE4Hp', 'js_a': 7, 'js_b': 14, 'js_c': 'sdmo'}
{'name': 'rLLUxF4f', 'js_a': 8, 'js_b': 16, 'js_c': 'sdmo'}
{'name': '5wt3UCvR', 'js_a': 9, 'js_b': 18, 'js_c': 'sdmo'}

解説

  • main()
  • dict_extract(item, prefix='')
    • 実装の本体です。
    • dict in dict in dict ...の事も考えて、再帰関数にしました。
    • valueの型がdictだったなら、再びvalueでdict_extractしてみる。
    • 最終的に返すdictのkeyが一意になるように、keyをアンダースコアでつないでみた。
    • 一意なことが確定しているのであれば、prefix += f'{key}_'部分をなくしていいかと。

余談

prefixをlistにしてjoinしたほうがスマートな気もします。
そのときは引数にlistを渡すのは避けましょう。
listはミュータブル、更新可能なオブジェクトです。
引数の初期値にミュータブルなオブジェクトを指定した場合、そのオブジェクトは関数定義時に生成されるので、該当の引数を省略して関数を呼び出すと同じオブジェクトが使われます。

コード

def string_arg2(s_arg=['hatsumi']):
    s_arg.append(' san')
    print(''.join(s_arg))

for i in range(10):
    string_arg2()

結果

hatsumi san
hatsumi san san
hatsumi san san san
hatsumi san san san san
hatsumi san san san san san
hatsumi san san san san san san
hatsumi san san san san san san san
hatsumi san san san san san san san san
hatsumi san san san san san san san san san
hatsumi san san san san san san san san san san

名刺管理サービスみたいな結果になりました。
ちなみにdictもミュータブルですのでお気をつけあそばせ。
初期化するときに一手間必要です。

def string_arg2(s_arg=None):
    if s_arg is None:
        s_arg = ['hatsumi']
    s_arg.append(' san')
    print(''.join(s_arg))

for i in range(10):
    string_arg2()

募集

  • 上記実装の標準関数はありそう。どう検索すれば見つかるか教えていただけると幸甚です。。
  • dict in dict って一般的な呼び方あるんですかね。入れ子辞書?
    略すとd in d になって、docker in dockerっぽくて紛らわしい・・
2
2
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2