使用Python将分隔的字符串和值转换为分层JSON

时间:2017-11-07 08:51:51

标签: python json tree hierarchical-data delimited

我的数据格式如下:

[['Director', 9010],
['Director - Product Manager', 9894],
['Director - Product Manager - Project Manager', 9080],
['Director - Product Manager - Project Manager - Staff', 5090],
['Director - Product Manager - Project Manager - Staff 2', 5087],
['Director - Product Manager - Project Manager 2', 9099],...]

并希望输出看起来像这样:

{
    'title': 'Director',
    'id': 9010,
    'children': [
        {
            'title': 'Product Manager',
            'id': 9894,
            'children': [
                {
                    'title': 'Project Manager',
                    'id': 9080,
                    'children': [
                        ...
                    ]
                },{
                    'title': 'Project Manager 2',
                    'id': 9099,
                    'children': [
                        ...
                    ]
                }],
                ...
            ]
        },
        ...
    ]
}

我一直在玩字典,但努力将ID与标题相匹配。任何建议都表示赞赏。

2 个答案:

答案 0 :(得分:2)

执行此操作的有效方法是将最外层设为列表而不是字典。当我们遍历标题字符串中的每个标题时,我们在当前列表中查找具有该标题的字典。如果当前列表中不存在标题,那么我们需要创建一个新的字典。如果它确实存在,那么我们将该dict的子列表设为新的当前列表并继续寻找下一个标题。

我还编写了一个递归prune函数,一旦我们输入了所有数据,就会删除所有空子列表,以防你想要这样做。

import json

lst = [
    ['Director', 9010],
    ['Director - Product Manager', 9894],
    ['Director - Product Manager - Project Manager', 9080],
    ['Director - Product Manager - Project Manager - Staff', 5090],
    ['Director - Product Manager - Project Manager - Staff 2', 5087],
    ['Director - Product Manager - Project Manager 2', 9099],
]

# Search for a matching name in the current list.
# If it doesn't exist, create it.
def insert(lst, name, idnum):
    for d in lst:
        if d['title'] == name:
            break
    else:
        d = {'title': name, 'id': idnum, 'children': []}
        lst.append(d)
    return d['children']

# Remove empty child lists
def prune(lst):
    for d in lst:
        if d['children']:
            prune(d['children'])
        else:
            del d['children']

# Insert the data into the master list
master = []
for names, idnum in lst:
    lst = master
    for name in [s.strip() for s in names.split(' - ')]:
        lst = insert(lst, name, idnum)

prune(master)

# Get the top level dict from the master list
data = master[0]
print(json.dumps(data, indent=4))

<强>输出

{
    "title": "Director",
    "id": 9010,
    "children": [
        {
            "title": "Product Manager",
            "id": 9894,
            "children": [
                {
                    "title": "Project Manager",
                    "id": 9080,
                    "children": [
                        {
                            "title": "Staff",
                            "id": 5090
                        },
                        {
                            "title": "Staff 2",
                            "id": 5087
                        }
                    ]
                },
                {
                    "title": "Project Manager 2",
                    "id": 9099
                }
            ]
        }
    ]
}

答案 1 :(得分:0)

d作为输入,使用。

遍历输入列表

由于每个子列表中都有两个元素,因此将迭代变量中的位置和ID保存为pid

示例,您正在处理列表['Director - Product Manager - Project Manager - Staff', 5090],

要获取每个位置的标题,您可以将您的位置拆分为-,并去除前导和尾随空格。例如,

>>> d[3][0]
'Director - Product Manager - Project Manager - Staff'
>>> map(str.strip,d[3][0].split('-'))
['Director', 'Product Manager', 'Project Manager', 'Staff']

输出dict以及前一个Staff位置被传递给递归搜索方法,并且它获取查找值的所有匹配,即Project Manager并返回一个列表。获取最后一场比赛。

>>> recursive_search([data,],'Product Manager')[-1]
{'children': [{'children': [{'id': 5090, 'title': 'Staff'}, {'id': 5087, 'title': 'Staff 2'}], 'id': 9080, 'title': 'Project Manager'}, {'id': 9099, 'title': 'Project Manager 2'}], 'id': 9894, 'title': 'Product Manager'}

您需要将新ID添加到上述结果的children键中!

结合以上所有,

d=[['Director', 9010],['Director - Product Manager', 9894],['Director - Product Manager - Project Manager', 9080],['Director - Product Manager - Project Manager - Staff', 5090],['Director - Product Manager - Project Manager - Staff 2', 5087],['Director - Product Manager - Project Manager 2', 9099],]

from pprint import pprint    
def recursive_search(items, key):
        found = []
        for item in items:
                if isinstance(item, list):
                        found += recursive_search(item, key)
                elif isinstance(item, dict):
                        if key in item.values():
                                found.append(item)
                        found += recursive_search(item.values(), key)
        return found
data={}
for p,id in d:
        desig = map(str.strip,p.split('-'))
        if len(desig)>1:
                res = recursive_search([data,],desig[-2])[-1]
                if res:
                        res['children']=res.get('children',[])
                        res['children'].append({'id':id,'title':desig[-1]})
        else:
                data = {'id':id,'title':p}

pprint.pprint(data)

输出:

{'children': [{'children': [{'children': [{'id': 5090, 'title': 'Staff'},
                                          {'id': 5087,
                                           'title': 'Staff 2'}],
                             'id': 9080,
                             'title': 'Project Manager'},
                            {'id': 9099, 'title': 'Project Manager 2'}],
               'id': 9894,
               'title': 'Product Manager'}],
 'id': 9010,
 'title': 'Director'}

参考:这里使用的recursive_search函数是通过提到here

的字典进行搜索的略微修改版本