旧それなりブログの跡地、画像やスタイルやJSなどが壊れてることがあります。

[Python] 再帰的にdictをwalkする関数

2011年8月7日

「自分の子リストを持つdictデータ」を再帰的に評価したかった

例えば以下のようなデータを

adict = {
    'name': u'波平',
    'children': [
        {
            'name': u'サザエ',
            'children':[{'name':u'タラオ', 'children':[]}],
        },
        {'name': u'カツオ', 'children':[]},
        {'name': u'ワカメ', 'children':[]},
    ]
}

こんな風に操作したいなと思いました

for child in 関数(adict):
print child['name'] # -> u'波平' から順次表示

walk_dict関数を作ったけど

というわけで、walk_dict(adict, children_key) という関数を作りました

・・・と、要件は満たせたんですが、何か変

for i in walk_dict(child, children_key):
    yield i

のところを、generatorを解除するのに1回しか回らんループをしてるのが特に変?

ということで

「○○モジュール使えばいいんじゃないの?お馬鹿なの?」
という、身も蓋もない意見を絶賛募集中です!

後、ついでにも程がありますが、JavaScriptでも同じような関数を募集中です!!

別解を貰った

@kenji4569 さんから別解を貰ったので、元解答と両方さらしておきます

# 自分
def walk_dict(adict, children_key):
    yield adict
    for child in adict[children_key]:
        for i in walk_dict(child, children_key):
            yield i

# @kenji4569 さん
def walk_dict(adict, children_key):
    from itertools import chain
        return chain([adict], *[walk_dict(child, children_key) for child in adict[children_key]])

JavaScript版

アルゴリズムは一緒です、JSに書き起こしただけ
イテレーターにはなってません

function walkObject(obj, childrenKey) {
    var sequence = [];
    sequence.push(obj);
    var children = obj[childrenKey];
    for (var i = 0; i < children.length; i++) {
        var child = children[i];
        sequence = sequence.concat(arguments.callee(child, childrenKey));
    }
    return sequence;
}