Groovy:比较两个惰性maps/jsons

Groovy: compare two lazy maps/jsons

我有两张 jsons/lazy 地图,格式如下所示。我现在需要比较它们,看看它们之间是否有任何区别。我将每组值组合在一个字符串中以便比较变得更快的原因,因为我的实际输入(即 json 消息)将非常大。

要求Json:

[["B1": 100, "B2": 200, "B3": 300, "B4": 400],["B1": 500, "B2": 600, "B3": 700, "B4": 800], ["B1": 900, "B2": 1000, "B3": 2000, "B4": 3000], ["B1": 4000, "B2": 5000, "B3": 6000, "B4": 7000]]

响应Json:

[["B1": 100, "B2": 200, "B3": 300, "B4": 400],["B1": 500, "B2": 600, "B3": 700, "B4": 800], ["B1": 900, "B2": 1000, "B3": 2000, "B4": 3000], ["B1": 4000, "B2": 5000, "B3": 6000, "B4": 7000], ["B1": 8000, "B2": 9000, "B3": 10000, "B4": 11000]]

我的代码如下所示,但不知何故我无法获得所需的结果。我无法弄清楚出了什么问题。我从响应 Json 中获取每个值并将其与 request-Json 中的任何值进行比较以查看是否存在差异。

def diffCounter = 0
Set diffSet = []

    respJson.each { respJ ->
                            reqJson.any {
                                        reqJ ->
                                        if (respJ.B1+respJ.B2+respJ.B3+respJ.B4 != reqJ.B1+reqJ.B2+reqJ.B3+reqJ.B4) {

                                            diffCounter += 1
                                            diffSet << [
                                                "B1" : respJ.B1,
                                                "B2" : respJ.B2,
                                                "B3" : respJ.B3,
                                                "B4" : respJ.B4
                                            ]
                                   
                                        }
                                
                            }

    }
println ("Difference Count: "+ diffCounter)
println ("Difference Set: "+ diffSet)

实际输出:

Difference Count: 5
Difference Set: [[B1:100, B2:200, B3:300, B4:400], [B1:500, B2:600, B3:700, B4:800], [B1:900, B2:1000, B3:2000, B4:3000], [B1:4000, B2:5000, B3:6000, B4:7000], [B1:8000, B2:9000, B3:10000, B4:11000]]

预期输出:

Difference Count: 1
Difference Set: [["B1": 8000, "B2": 9000, "B3": 10000, "B4": 11000]]

注意: 请求-json 也可能比响应-json 大,所以在这种情况下我需要存储从 request-json 获得的差异进入 diffSet.

这方面的任何 inputs/suggestions 都会有所帮助。

正如@daggett 提到的,如果您的 JSON 变得更多 nested/complicated,您将需要使用一个库来为您完成这项工作。

在纯元素列表的用例中(值可以是 concatenated/added 以形成该元素的唯一键)这样做没有问题 'manually'.

您的代码的问题在于您检查是否有任何 reqJson 条目具有 不同的 计数,对于 2+ 个不同的 reqJson 条目总是是的。

您真正想要检查的是是否有匹配的 reqJson 条目具有 相同的 计数。如果您找不到任何匹配的条目,那么您就知道该条目仅存在于 respJson.

def diffCounter = 0
Set diffSet = []

respJson.each { respJ ->
    def foundMatching = reqJson.any { reqJ ->
        respJ.B1 + respJ.B2 + respJ.B3 + respJ.B4 == reqJ.B1 + reqJ.B2 + reqJ.B3 + reqJ.B4
    }
    if (!foundMatching) {
        diffCounter += 1
        diffSet << [
                "B1" : respJ.B1,
                "B2" : respJ.B2,
                "B3" : respJ.B3,
                "B4" : respJ.B4
        ]
    }
}
println ("Difference Count: "+ diffCounter)
println ("Difference Set: "+ diffSet)

你提到 reqJson 可以变得比 respJson 大,在那种情况下你想在比较中切换两个数组的角色,这样你总是从更大的数组。一个技巧是先交换两个变量。

if (reqJson.size() > respJson.size()) {
    (reqJson, respJson) = [respJson, reqJson]
}

注意这个算法的时间复杂度是O(m * n * 2i),意思是随着两个数组(mn,这里是5和4), 乘以 属性 访问的计数,我们在两个元素上进行每个循环(i 两个元素,这里是 4 因为有 4 个 Bs),因为我们可能检查每个元素对于较大数组的每个元素,较小数组的一次。

所以如果数组有数万个元素长,这将变得非常慢。将其加速到 O(m * i + n * i) 的一种简单方法是:

  1. 从较小数组的串联 messages/added 值中创建一个集合 smallArrayKeys
  2. 遍历更大的数组,检查它的串联消息是否包含在 smallArrayKeys 集合中,如果不包含则它只存在于更大的数组中。