Python - 获取两个 Json 文件的交集

4
我正在寻找一种计算两个JSON文件交集的选项。我已经搜索过了,发现可以使用集合来解决我的问题。这个方法“还行”。但是我需要更详细的交集视图,这就是问题开始的地方。 如何计算交集:
def calcIntersect(ValidationFile, json_object1, json_object2):

with open(ValidationFile) as schema_file:
    schema = j.load(schema_file)
    js.Draft4Validator.check_schema(schema)

with open(json_object1) as spec_file:
    spec1 = j.load(spec_file, object_pairs_hook=OrderedDict)
    js.validate(spec1, schema)

with open(json_object2) as spec_file:
    spec2 = j.load(spec_file, object_pairs_hook=OrderedDict)
    js.validate(spec2, schema)

x = set(spec1) & set(spec2)

print(x)

示例数据1:

{
    "Car":{
        "Brand":"Audi",
        "Nationality":"Germany",
        "Modelname":"A6"
    },
    "Engine":{
        "cubic capacity":"2967",
        "Enginetype":"V6",
        "Fuel":"Diesel",
        "MaxSpeed":"250"

    },
    "Colors":{
        "Carcolor":"Black",
        "Interiorrcolor":"white"
    }
}

示例数据2:

{
    "Car":{
        "Brand":"Audi",
        "Nationality":"USA",
        "Modelname":"A6"
    },
    "Engine":{
        "cubic capacity":"2995",
        "Enginetype":"V6",
        "Fuel":"Petrol",
        "MaxSpeed":"250"

    },
    "Colors":{
        "Carcolor":"Black",
        "Interiorrcolor":"Black"
    }
}

例子输出:

{'Car', 'Colors', 'Engine'}

这只是“键”,但我需要字典。目前它给我这些键来表示其中有一个交集。也许在“汽车”中,两个文件都有一辆“奥迪”,但国籍不同,因为一辆车是在美国生产的,另一辆车是在德国生产的。但它仍然返回“汽车”,而不是“奥迪”。
我希望我能描述清楚我的问题。这是我的第一个问题...

如果我们知道spec1 / spec2的示例数据,那将有助于理解。 - user2358582
@user2358582 好的,我已经编辑过了,并添加了描述情况的示例数据。感谢您的建议! - Dome A.
3个回答

2
以下代码段灵感来自@likeon的回答,将为您提供一个字典,其键将是规格中相交对象的键,值将是包含相交对象的数组。
intersect = { key: [o, spec2[key]] for key, o in spec1.iteritems()
                                   if key in spec2 };

编辑: 如果您正在使用Python 3,则必须使用items而不是iteritems

intersect = { key: [o, spec2[key]] for key, o in spec1.items()
                                   if key in spec2 };

好的,我想我得到了一个“默认”的解决方案。谢谢!我会试一下。 - Dome A.
好的,我测试过了。运行良好。非常感谢!对于使用Python 3.x的人来说,你需要将“spec1.iteritems()”更改为“spec1.items()”。 - Dome A.

1
为什么不直接遍历spec1并将其与spec2的值进行比较,像这样:
x = {k: v for k, v in spec1.iteritems() if k in spec2 and spec2[k] == v}

这是我目前计划使用的东西。但我认为会有更好的选择。谢谢! - Dome A.
这将返回所有值,而不仅仅是匹配的元素!如果在spec2上找不到k,它将引发一个keyerror异常。 - YOBA
不完全是这样,它只会返回 spec1 的值。我冒昧地分叉了你的代码,所以它现在会返回两个值。 - Quentin Roy
@YOBA 是的,示例代码是正确的,但是想法是遍历所有元素并进行比较。 - Dome A.
好的,如果这就是你要找的,只需使用spec2.get(k) == v,以避免keyerror异常。 - YOBA
@YOBA 这里可能有这样一种情况,即spec1具有具有None值的键,而spec没有。在这种情况下,该键将显示为交集,但实际上不应该。 - likeon

0
你需要一个递归解决方案:
json1 = {
    "Car": {
        "Brand": "Audi",
        "Nationality": "Germany",
        "Modelname": "A6"
    },
    "Engine": {
        "cubic capacity": "2967",
        "Enginetype": "V6",
        "Fuel": "Diesel",
        "MaxSpeed": "250"
    },
    "Colors": {
        "Carcolor": "Black",
        "Interiorrcolor": "white"
    }
}

json2 = {
    "Car": {
        "Brand": "Audi",
        "Nationality": "USA",
        "Modelname": "A6"
    },
    "Engine": {
        "cubic capacity": "2995",
        "Enginetype": "V6",
        "Fuel": "Petrol",
        "MaxSpeed": "250"
    },
    "Colors": {
        "Carcolor": "Black",
        "Interiorrcolor": "Black"
    }
}


def common_dict(d1, d2):
    output = {}
    for k in set(d1) & set(d2):
        o1, o2 = d1[k], d2[k]
        if isinstance(o1, dict) and isinstance(o2, dict):
            output[k] = common_dict(o1, o2)
        elif o1 == o2:
            output[k] = o1
    return output

print common_dict(json1, json2)
# {'Engine': {'MaxSpeed': '250', 'Enginetype': 'V6'}, 'Car': {'Brand': 'Audi', 'Modelname': 'A6'}, 'Colors': {'Carcolor': 'Black'}}

在定义o1和o2的那一行出现了“TypeError: string indices must be integers”。 - Dome A.
你传递什么给common_dict? - Łukasz Rogalski
三个文件。一个Shemefile和两个Json文件。 - Dome A.
@DomeA。common_dict需要传入两个参数,你是如何传递三个对象的?另外,“json文件”是什么?它是一个文件对象吗?Python字典?字符串对象?它应该是一个Python字典。 - Łukasz Rogalski
是的,抱歉我传递了两个对象。但它们是文件对象。但现在我有一个解决方案。我正在按照Quentin建议的遍历元素。我现在将对其进行测试。但感谢您的解决方案,我也会尝试它。 - Dome A.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接