是否有一种pythonic方式来处理树形结构的dict键?

时间:2016-07-20 19:59:46

标签: python dictionary tree

我正在寻找一个pythonic成语,将一个键列表和一个值转换成一个带有嵌套键的dict。例如:

dtree(["a", "b", "c"]) = 42
    or
dtree("a/b/c".split(sep='/')) = 42

将返回嵌套的字典:

{"a": {"b": {"c": 42}}}

这可用于将带有分层键的一组值转换为树:

dtree({
    "a/b/c": 10,
    "a/b/d": 20,
    "a/e": "foo",
    "a/f": False,
    "g": 30 })

would result in:

{   "a": {
        "b": {
            "c": 10,
            "d": 20 },
        "e": foo",
        "f": False },
    "g": 30 }

我可以编写一些FORTRANish代码来使用强力和多个循环进行转换,也许collections.defaultdict,但它看起来像是一种具有拆分和连接的语言,切片和理解应该有一个原语可以转换列表将["a","b","c"]字符串转换为嵌套的dict键["a"]["b"]["c"]。如果不在dict表达式字符串上使用eval,最简单的方法是什么?

2 个答案:

答案 0 :(得分:11)

  

我正在寻找一个pythonic成语,将一个键列表和一个值转换成一个dict,并嵌入这些键。

reduce(lambda v, k: {k: v}, reversed("a/b/c".split("/")), 42)
  

这可用于将带有分层键的一组值转换为树

def hdict(keys, value, sep="/"):
    return reduce(lambda v, k: {k: v}, reversed(keys.split(sep)), value)

def merge_dict(trg, src):
    for k, v in src.items():
        if k in trg:
            merge_dict(trg[k], v)
        else:
            trg[k] = v

def hdict_from_dict(src):
    result = {}
    for sub_hdict in map(lambda kv: hdict(*kv), src.items()):
        merge_dict(result, sub_hdict)
    return result

data = {
    "a/b/c": 10,
    "a/b/d": 20,
    "a/e": "foo",
    "a/f": False,
    "g": 30 }

print(hdict_from_dict(data))

使用collections.defaultdict

的另一个整体解决方案
import collections

def recursive_dict():
    return collections.defaultdict(recursive_dict)

def dtree(inp):
    result = recursive_dict()
    for keys, value in zip(map(lambda s: s.split("/"), inp), inp.values()):
        reduce(lambda d, k: d[k], keys[:-1], result)[keys[-1]] = value
    return result

import json
print(json.dumps(dtree({
    "a/b/c": 10,
    "a/b/d": 20,
    "a/e": "foo",
    "a/f": False,
    "g": 30 }), indent=4))

答案 1 :(得分:0)

或者只是为了咧嘴笑,因为reduce是自切片面包以来最酷的东西,你可以通过两次使用它来保存一个SLOC: - )

def dmerge(x, y):
    result = x.copy()
    k = next(iter(y))
    if k in x:
        result[k] = dmerge(x[k], y[k])
    else:
        result.update(y)
    return result

def hdict(keys, value, sep="/"):
    return reduce(lambda v, k: {k: v}, reversed(keys.split(sep)), value)

def hdict_from_dict(src):
    return reduce(lambda x, y: dmerge(x, y), [hdict(k, v) for k, v in src.items()])

data = {
    "a/b/c": 10,
    "a/b/d": 20,
    "a/e": "foo",
    "a/f": False,
    "g": 30 }

print("flat:", data)
print("tree:", hdict_from_dict(data))