使用Python将包含dict&list的两个json文件合并到单个json中?

时间:2018-09-20 05:32:25

标签: python json

我正在尝试使用python将两个JSON文件合并为一个JSON。

文件1:

{
    "key1":    "protocol1",
    "key2":     [
            {
                    "name": "user.name",
                    "value": "user@EXAMPLE123.COM"
            },
            {
                    "name": "user.shortname",
                    "value": "user"
            },
            {
                    "name": "proxyuser.hosts",
                    "value": "*"
            },
            {
                    "name": "kb.groups",
                    "value": "hadoop,users,localusers"
            },        
            {
                    "name": "proxy.groups",
                    "value": "group1, group2, group3"
            },
            {
                    "name": "internal.user.groups",
                    "value": "group1, group2"
            }
    ]
}

文件2:

{
    "key1":    "protocol1",
    "key2":     [
            {
                    "name": "user.name",
                    "value": "user@EXAMPLE456.COM"
            },
            {
                    "name": "user.shortname",
                    "value": "user"
            },
            {
                    "name": "proxyuser.hosts",
                    "value": "*"
            },
            {
                    "name": "kb.groups",
                    "value": ""
            },        
            {
                    "name": "proxy.groups",
                    "value": "group3, group4, group5"
            },
            {
                    "name": "internal.groups",
                    "value": "none"
            }
    ]
}

最终预期结果:

{
    "key1":    "protocol1",
    "key2":     [
            {
                    "name": "user.name",
                    "value": "user@EXAMPLE123.COM, user@EXAMPLE456.COM"
            },
            {
                    "name": "user.shortname",
                    "value": "user"
            },
            {
                    "name": "proxyuser.hosts",
                    "value": "*"
            },
            {
                    "name": "kb.groups",
                    "value": "hadoop,users,localusers"
            },        
            {
                    "name": "proxy.groups",
                    "value": "group1, group2, group3, group4, group5"
            },
            {
                    "name": "internal.user.groups",
                    "value": "group1, group2"
            },
            {
                    "name": "internal.groups",
                    "value": "none"
            }
    ]
}

我需要根据以下规则进行合并:

  1. 如果两个文件中list(key2)中的'name'键匹配,则将这些值连接起来。

    例如

    文件1:

    "key2": [{"name" : "firstname", "value" : "bob"}]
    

    文件2:

    "key2": [{"name" : "firstname", "value" : "charlie"}]
    

    最终输出:

    "key2": [{"name" : "firstname", "value" : "bob, charlie"}]
    

附加值时的一些注意事项:

  • 如果两个文件在“ value”中均包含重复的值,则最终结果应仅为值的并集。

  • 如果任何“值”包含“ *”,则最终值应为“ *”。

    1. 如果第二个JSON文件中的“名称”键不存在于第一个文件中,请将其添加到第一个文件中。

我已经编写了一个python脚本来加载两个JSON文件并合并它们,但似乎只是将所有内容连接到了第一个JSON文件中。

    def merge(a, b):
        "merges b into a"
        for key in b:
            if key in a:# if key is in both a and b
                if key == "key1":
                    pass
                elif key == "key2":
                    for d1, d2 in zip(a[key], b[key]):
                        for key, value in d1.items():
                            if value != d2[key]:
                                a.append({"name": d2[key], "value": d2["value"]})
                else:
                  a[key] = a[key]+ b[key]
            else: # if the key is not in dict a , add it to dict a
                a.update({key:b[key]})
        return a

有人可以指出我如何比较两个文件中“名称”部分的值和key2的列表,并将“值”中的值连接起来吗?

3 个答案:

答案 0 :(得分:2)

这是一个使用字典以线性时间运行的解决方案,该字典通过给定a键在name中快速查找项目。字典b的{​​{1}}列表经过一次迭代,并且key2根据需要在恒定时间内进行修改。集合用于消除重复项并处理星号。

a

示例输出:

def merge(a, b):
    lookup = {o['name']: o for o in a['key2']}

    for e in a['key2']:
        e['value'] = set([x.strip() for x in e['value'].split(",")])

    for e in b['key2']:
        if e['name'] in lookup:
            lookup[e['name']]['value'].update([x.strip() for x in e['value'].split(",")])
        else:
            e['value'] = set([x.strip() for x in e['value'].split(",")])
            a['key2'].append(e)

    for e in a['key2']:
        if "*" in e['value']:
            e['value'] = "*"
        else:
            e['value'] = ", ".join(sorted(list(e['value'])))

还有一个测试repl

答案 1 :(得分:1)

不能保证a["key2"]b["key2"]中元素的顺序相同,因此您应该建立一个从"name"值到a["key2"]中索引的映射,然后浏览b["key2"],将每个"name"值与该字典进行比较。

代码可能是:

def merge(a, b):
    "merges b into a"
    for key in b:
        if key in a:# if key is in both a and b
            if key == "key2":
                # build a mapping from names from a[key2] to the member index
                akey2 = { d["name"]: i for i,d in enumerate(a[key]) }
                for d2 in b[key]:      # browse b["key2"]
                    if d2["name"] in akey2:   # a name from a["key2"] matches
                        a[key][akey2[d2["name"]]]["value"] += ", " + d2["value"]
                    else:
                        a[key].append(d2)     # when no match
        else: # if the key is not in dict a , add it to dict a
            a[key] = b[key]
    return a

然后您可以对其进行测试:

a = {"key1":    "value1",
     "key2": [{"name" : "firstname", "value" : "bob"}]
     }
b = {"key1":    "value2",
     "key2": [{"name" : "firstname", "value" : "charlie"},
          {"name" : "foo", "value": "bar"}]
     }
merge(a, b)

pprint.pprint(a)

给出预期的结果:

{'key1': 'value1',
 'key2': [{'name': 'firstname', 'value': 'bob, charlie'},
          {'name': 'foo', 'value': 'bar'}]}

答案 2 :(得分:0)

如果它不在新字典中,则只需遍历键即可;如果将两个值合并,则将其添加进来

d1 = {"name" : "firstname", "value" : "bob"}
d2 = {"name" : "firstname", "value" : "charlie"}
d3 = {}

for i in d1:
    for j in d2:
        if i not in d3:
            d3[i] = d1[i]
        else:
            d3[i] = '{}, {}'.format(d1[i], d2[i])

print(d3)
(xenial)vash@localhost:~/python/stack_overflow$ python3.7 formats.py 
{'name': 'firstname, firstname', 'value': 'bob, charlie'}