Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
合并包含dict&;的两个json文件;使用python将列表转换为单个json?_Python_Json - Fatal编程技术网

合并包含dict&;的两个json文件;使用python将列表转换为单个json?

合并包含dict&;的两个json文件;使用python将列表转换为单个json?,python,json,Python,Json,我正在尝试使用python将两个JSON文件合并成一个JSON 文件1: { "key1": "protocol1", "key2": [ { "name": "user.name", "value": "user@EXAMPLE123.COM" }, { "name": "u

我正在尝试使用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"
            }
    ]
}
"key2": [{"name" : "firstname", "value" : "charlie"}]
最终预期结果:

{
    "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"
            }
    ]
}
我需要根据以下规则进行合并:

  • 如果
    列表(key2)
    中的“name”键在两个文件中匹配,则将值连接起来

    e、 g

    文件1:

    "key2": [{"name" : "firstname", "value" : "bob"}]
    
    文件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"
                }
        ]
    }
    
    "key2": [{"name" : "firstname", "value" : "charlie"}]
    
    最终输出:

    "key2": [{"name" : "firstname", "value" : "bob, charlie"}]
    
  • 附加值时的一些注意事项:

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

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

    • 如果第二个JSON文件中的“name”键在第一个文件中不存在,请将其添加到第一个文件中
    我编写了一个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
    

    有人能指出我如何将“name”部分的值与两个文件中的key2列表进行比较,并将“value”中的值串联起来吗?

    如果没有在新的dict中,只需循环键,如果合并了两个值,则添加它

    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)
    

    下面是一个线性时间运行的解决方案,使用字典在给定
    名称
    键的
    中快速查找项目。字典
    b
    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'])))
    
    样本输出:

    key1:
    协议1
    关键2:
    {'name':'user.name','value':'user@EXAMPLE123.COM, user@EXAMPLE456.COM'}
    {'name':'user.shortname','value':'user'}
    {'name':'proxyuser.hosts','value':'*'}
    {'name':'kb.groups','value':',hadoop,localusers,users'}
    {'name':'proxy.groups','value':'group1,group2,group3,group4,group5'}
    {'name':'internal.user.groups','value':'group1,group2'}
    {'name':'internal.groups','value':'none'}
    
    不能保证
    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'}]}
    

    一旦你读取并反序列化了数据,它就不再与JSON有关了,因此你可以减少你的问题。@Ulrich Eckhardt感谢你指出这一点,但写回第一个文件不会将其序列化吗?@ggorlen:我只是在发布我的答案后才看到你的答案,然后意识到它们是一样的。我把这个放在这里,因为它集成了OP的merge函数中的代码。如果您在回答中这样做,并在评论中ping我,我将删除此项。我们是否可以避免在此处附加重复值(a中已存在值)?@TusharKarkera:是的。将两个
    value
    字符串拆分为多个集合就足够了,将两个集合合并,然后合并结果。懒得去做。。。无论如何,它需要一个精确的值格式规范。我已经添加了输入格式的精确规范,以及如何在我的原始问题编辑中合并它们。如果有什么不清楚的地方,请告诉我。谢谢你的帮助@TusharKarkera:正如我已经说过的,我太懒了,而ggorlen的答案已经包含了我本可以为你做的事情,ggorlen和@Serge Ballesta为你的答案。代码可以很好地比较“name”值,但对于以下情况,需要临时修改:如果“value”:“*”,那么当我们合并相同“name”的值时;理想情况下,它应该只打印一个“*”,但现在它打印“*,*”。我并不是100%地遵循——你是说你希望
    列表仅为唯一项?请用新的要求更新您的问题,我会在有时间时更新我的答案。更新原始问题以更清楚,谢谢!此行不追加值,而是覆盖
    查找[e['name']['value']=e['value']]
    我确实尝试了追加,尽管我面临的一个问题是重复值。因为“value”中可能有两个列表中匹配的值。我尝试使用set()消除重复项,但得到的错误是set不是JSON Serializable我不理解您的更新版本。除了
    proxy.groups
    键外,所有内容都已清除。文件1和文件2都有值
    group1、group2、group3
    。我希望合并的输出是
    group1、group2、group3
    ,但不知何故,您正在寻找
    group1、group2、group3、group4、group5
    ,这两个组都很奇怪,因为两个组是由蓝色组成的,如果您对数字组扩展感兴趣,我希望出现6个组而不是5个组。请解释一下你是如何实现这一转变的。在此期间,我更新了我的代码,以处理除此edge案例之外的所有问题。