5

Python で任意にネストされた JSON 形式の dict/array で動作し、含まれるすべての変数名をキーイングする文字列のリストを無限の深さまで返す関数を探しています。それで、オブジェクトが...

x = {
    'a': 'meow',
    'b': {
        'c': 'asd'
    },
    'd': [
        {
            "e": "stuff",
            "f": 1
        },
        {
            "e": "more stuff",
            "f": 2
        }
    ]
}

mylist = f(x)戻ってきます...

>>> mylist
['a', 'b', 'b.c', 'd[0].e', 'd[0].f', 'd[1].e', 'd[1].f']
4

4 に答える 4

3

これは楽しいものです。再帰を使用して解決しました。

def parse(d):
    return parse_dict(d)

def parse_dict(d):
    items = []
    for key, val in d.iteritems():
        if isinstance(val, dict):
            # use dot notation for dicts
            items += ['{}.{}'.format(key, vals) for vals in parse_dict(val)]
        elif isinstance(val, list):
            # use bracket notation for lists
            items += ['{}{}'.format(key, vals) for vals in parse_list(val)]
        else:
            # just use the key for everything else
            items.append(key)
    return items

def parse_list(l):
    items = []
    for idx, val in enumerate(l):
        if isinstance(val, dict):
            items += ['[{}].{}'.format(idx, vals) for vals in parse_dict(val)]
        elif isinstance(val, list):
            items += ['[{}]{}'.format(idx, vals) for vals in parse_list(val)]
        else:
            items.append('[{}]'.format(val))
    return items

ここに私の結果があります:

>>> parse(x)
['a', 'b.c', 'd[0].e', 'd[0].f', 'd[1].e', 'd[1].f']

編集

Fj の回答が気に入ったので、ここでもジェネレーターを使用しています。

def parse(d):
    return list(parse_dict(d))

def parse_dict(d):
    for key, val in d.iteritems():
        if isinstance(val, dict):
            # use dot notation for dicts
            for item in parse_dict(val):
                yield '{}.{}'.format(key, item)
        elif isinstance(val, list):
            # use bracket notation
            for item in parse_list(val):
                yield '{}{}'.format(key, item)
        else:
            # lowest level - just use the key
            yield key

def parse_list(l):
    for idx, val in enumerate(l):
        if isinstance(val, dict):
            for item in parse_dict(val):
                yield '[{}].{}'.format(idx, item)
        elif isinstance(val, list):
            for item in parse_list(val):
                yield '[{}]{}'.format(idx, item)
        else:
            yield '[{}]'.format(val)

同じ結果:

>>> parse(x)
['a', 'b.c', 'd[0].e', 'd[0].f', 'd[1].e', 'd[1].f']
于 2013-07-30T17:26:57.037 に答える
2

オブジェクトの最上位がリスト (JSON 用語では配列) である可能性がある場合、出力形式は機能しませ["foo", "bar"]['[0]', '[1]']。FJの回答をわずかに変更してオブジェクトの名前を渡すことで、これを解決できます。

def paths(container, name):
    if isinstance(container, list):
        for i, element in enumerate(container):
            for path in paths(element, "%s[%d]" % (name, i)):
                yield path
    elif isinstance(container, dict):
        for k, element in container.items():
            for path in paths(element, "%s.%s" % (name, k)):
                yield path
    else:
        yield name

使用法:

>>> list(paths(x, "x"))
['x.a', 'x.b.c', 'x.d[0].e', 'x.d[0].f', 'x.d[1].e', 'x.d[1].f']
>>> list(paths(["foo", "bar"], "array"))
['array[0]', 'array[1]']

Python 3.3 では、yield fromこれを少しきれいにする構文が導入されています。

def paths(container, name):
    if isinstance(container, list):
        for i, element in enumerate(container):
            yield from paths(element, "%s[%d]" % (name, i))
    elif isinstance(container, dict):
        for k, element in container.items():
            yield from paths(element, "%s.%s" % (name, k))
    else:
        yield name
于 2013-07-30T17:35:25.457 に答える