91024


以下のようにDictionaryを変換して多次元化するコードを書きたいのですが、可読性と速度の良いコードについてアドバイスいただけないでしょうか。

[code]

    before_dict = {
        'Book' : 'Wood',
        'Chapter--1' : 'Leaves',
        'Chapter--2' : 'Branches',
        'Chapter--3' : 'Trunk',
        'Section--1--Chapter' : 1,
        'Section--1--Title' : 'Green',
        'Section--2--Chapter' : 1,
        'Section--2--Title' : 'Russet',
    }
    
[/code]

変換後は以下のような多次元にしたいと思います。

[code]

    after_dict = {
        'Book' : 'Wood',
        'Chapter' : {'1' : 'Leaves', '2' : 'Branches', '3' : 'Trunk'}
        'Section' : {
            '1' : { 'Chapter' : '1', 'Title' : 'Green' },
            '2' : { 'Chapter' : '2', 'Title' : 'Russet' }
        }
    }
    
[/code]

CakePHPからDjangoに乗り換えたのですが、CakePHPでは  
<input name="var[chapter][1]" ...>  
のようにビューを作ると、コントローラで受け取ったPOSTデータも多次元配列になっていたので  
困らなかったのですが、Djangoではこれが手動でやるしかないのかと悩みながらの質問です。

よろしくお願いします。

=== 追記 ===  
自分でやってみて、こんな風に書けば4階層までは希望通り動いたのですが・・・あまりにもかっこ悪いのでどうにかしたいと思っています。

[code]

    after_dict={}
    
    for key,val in before_dict.items():
    
        key2 = key.split('--')
    
        if len(key2)==1:
            after_dict[key2[0]] = val
    
        elif len(key2)==2:
            if(after_dict.get(key2[0])==None):
                after_dict[key2[0]] = {}
            after_dict[key2[0]][key2[1]] = val
    
        elif len(key2)==3:
            if(after_dict.get(key2[0])==None):
                after_dict[key2[0]] = {}
                after_dict[key2[0]][key2[1]] = {}
            if(after_dict.get(key2[0]).get(key2[1])==None):
                after_dict[key2[0]][key2[1]] = {}
            after_dict[key2[0]][key2[1]][key2[2]] = val
    
        elif len(key2)==4:
            if(after_dict.get(key2[0])==None):
                after_dict[key2[0]] = {}
                after_dict[key2[0]][key2[1]] = {}
                after_dict[key2[0]][key2[1]][key2[2]] = {}
            if(after_dict.get(key2[0]).get(key2[1])==None):
                after_dict[key2[0]][key2[1]] = {}
                after_dict[key2[0]][key2[1]][key2[2]] = {}
            if(after_dict.get(key2[0]).get(key2[1]).get(key2[2])==None):
                after_dict[key2[0]][key2[1]][key2[2]] = {}
            after_dict[key2[0]][key2[1]][key2[2]][key2[3]] = val
    
    
[/code]


CC BY-SA 4.0
2022-09-10T00:44:12.220
91021
2022-09-10T07:28:53.527
2022-09-10T04:08:01.210
51774
51774
question
python django
PythonのDictionary多次元化


再帰関数を使った方法  
(元の dictの値に数値が入ってるのを, 文字列変換するなら以下の通り)

[code]

    def fn(d, ks, v):
        k = ks[0]
        if len(ks) == 1:
            d[k] = str(v)   # 文字列へ変換する場合
            #d[k] = v   # 値そのまま使用する場合
        else:
            sdict = d.setdefault(k, {})
            fn(sdict, ks[1:], v)
    
    after_dict = {}
    for k,v in before_dict.items():
        fn(after_dict, k.split('--'), v)
    
[/code]

* * *

【追記】  
`if dct.get(key) == None:` のような条件判断は

  * `None`, `True`, `False` などとの比較判定には `v is None` などのように `is` を使うほうがよい (比較的わかりやすい ＆ 高速) (但し `v is True` は **場合によっては** `v` のみがよいかも)
  * `key`に対する値が `None`もあり得る場合 これでは判定できないので `key in dct` や `key not in dct` が望ましい


CC BY-SA 4.0
2022-09-10T05:42:50.067
91024
2022-09-10T07:28:53.527
2022-09-10T07:28:53.527
43025
43025
91021
answer