Python:从key:value对的字符串创建一个嵌套的dict

时间:2018-04-30 12:35:43

标签: python list dictionary multidimensional-array

我有这样的字典:

{"key1:key2[0]:key3[0]": "1234",
 "key1:key2[0]:key4[0]:key5": "4567",
 "key1:key2[1]:key3[0]": "789",
 "key1:key2[1]:key4[1]:key5": "12345"}

键是表示目标字典中每个最终值的谱系的描述性方式。 :将父键与其子键分开,[]表示以前键的值是列表,并且大括号之间存在索引。

鉴于此,我如何构建像

这样的字典
{
   "key1":{
      "key2":[
         {
            "key3":["1234"],
            "key4":[{"key5":"4567"}]
         },
         {
            "key3":["789"],
            "key4":[{"key5":"12345"}]
         }
      ]
   }
}

我试图做这样的事情:

result_dict = {}

def populate(target_path, value):
    current_point_in_path = None
    t = result_dict
    target_path = target_path.split(":")
    for i, each_key in enumerate(target_path):
        list_index = re.findall(r'\[(.*?)\]', each_key)
        if len(list_index) > 1:
            raise Exception("not allowed")
        elif len(list_index) == 1:
            index = int(list_index[0])
            key_before = each_key.split(index)[0]
            if not isinstance(result_dict[key_before], list):
                t = t.setdefault(key_before, [])
                if i+1 == len(target_path):
                    # the issue is that this insert won't return a pointer to the current index element like setdefault would do
                    # alternate soultions are wc
                    t.insert(index, value)
                else:
                    t.insert(index, {})

        else:
            if i + 1 == len(target_path):
                t = t.setdefault(each_key, value)
            else:
                t = t.setdefault(each_key, {})

我无法在这里完成部分代码。也许我需要一个更好的设计与我的描述性语言。欢迎任何建议。

2 个答案:

答案 0 :(得分:1)

您可以将itertools.groupby与递归一起使用:

import re, itertools
d = {"key1:key2[0]:key3": "1234", "key1:key2[0]:key4": "4567", "key1:key2[1]:key3": "789", "key1:key2[1]:key4": "12345"}
new_d = [(re.findall('\w+', a), b) for a, b in d.items()]
def last_group(d):
  return [{a[-1]:c for a, c in list(b)} for _, b in itertools.groupby(sorted(d, key=lambda x:x[0][1]), key=lambda x:x[0][1])]

def group_data(d):
   return {a:(lambda x:group_data([(c[1:], d) for c, d in x]) if all(len(c) > 3 for c, _ in x) else last_group(x))(list(b)) for a, b in itertools.groupby(sorted(d, key=lambda x:x[0][0]), key=lambda x:x[0][0])}

print(group_data(new_d))

输出:

{'key1': {'key2': [{'key3': '1234', 'key4': '4567'}, {'key3': '789', 'key4': '12345'}]}}

答案 1 :(得分:1)

你可以使用这个怪物:

def populate(result_dict, target_path, value):
    # split path
    target_path = re.findall(r"[^:]+?(?=\[|:|$)|\[\d+?\]", target_path)
    # prepare path
    for i, element in enumerate(target_path):
        if element[0] == "[" and element[-1] == "]":
            element = int(element[1:-1])
        target_path[i] = element
    current = result_dict
    for i, element in enumerate(target_path[:-1]):
        if isinstance(element, str):  # dict index
            if element not in current:  # create new entry
                if isinstance(target_path[i + 1], str):  # next is a dict
                    current[element] = {}
                else:  # next is a list
                    current[element] = []
        elif isinstance(element, int):  # list index
            if element >= len(current):  # create new entry
                current.extend(None for _ in range(element-len(current)+1))
            if current[element] is None:
                if isinstance(target_path[i + 1], str):  # next is a dict
                    current[element] = {}
                else:  # next is a list
                    current[element] = []
        current = current[element]
    if isinstance(target_path[-1], int):
        current.append(value)
    else:
        current[target_path[-1]] = value

您可以使用此代码填写字典:

result_dict = {}
for key, value in {"key1:key2[0]:key3[0]": "1234",
                   "key1:key2[0]:key4[0]:key5": "4567",
                   "key1:key2[1]:key3[0]": "789",
                   "key1:key2[1]:key4[1]:key5": "12345"}.items():
    populate(result_dict, key, value)
print(json.dumps(result_dict, indent=4))

打印:

{
    "key1": {
        "key2": [
            {
                "key3": [
                    "1234"
                ],
                "key4": [
                    {
                        "key5": "4567"
                    }
                ]
            },
            {
                "key3": [
                    "789"
                ],
                "key4": [
                    null,
                    {
                        "key5": "12345"
                    }
                ]
            }
        ]
    }
}