【问题标题】:If statements in Groovy ClosuresGroovy 闭包中的 if 语句
【发布时间】:2014-02-11 09:30:03
【问题描述】:

我正在尝试编写一个小型递归闭包来解决父子迭代问题。在某个时刻,我需要在递归调用闭包之前检查其他孩子是否存在。我使用 IF 进行检查,但由于某种原因,if 总是返回 true。

使用包含的对象更新代码

有一个 Json 对象,其结构为 Parent Children(在下面的代码中称为 jsonArray)

   [
    {
        "id": "1",
        "name": "No Children" //And yet the if condition is true -> element.children
    },
    {
        "id": "2",
        "name": "Does not like Children either"
    },
    {
        "id": "123",
        "name": "Some Parent Element",
        "children": [
            {
                "id": "123123",
                "name": "NameWhatever"
            },
            {
                "id": "123123123",
                "name": "Element with Additional Children",
                "children": [
                    {
                        "id": "123123123",
                        "name": "WhateverChildName"
                    },
                    {
                        "id": "12112",
                        "name": "NameToMap"
                    }
                ]
            }
        ]
    }
]

还有一个 ArrayList 对象,它没有 ID,需要从 jsonArray 中的迭代中检索它们, 这被称为elementsToGetID,我过于简单化了:

["count": 2741,"value": "NameToMap" ], ["count": 133,"value": "OtherName" ]

这两个 for 循环是很久以前写的,我正在尝试编写递归闭包以更深入地了解孩子

for(int i=0; i<elementsToGetID.size(); i++){
    for(int j=0; j<jsonArray.size(); j++){

        { element ->
            if(element.name == elementsToGetID[i].value){
                elementsToGetID[i]["id"] = element.id
            }
            if (element.children) {
                element.children.each {inst ->
                    log.info "Element to continue function " +inst
                    call(inst) //This call fails
                }
            }
        }(jsonArray[j])

    }
}

【问题讨论】:

  • 你能给出一些示例 json 结构以便我们测试它吗?
  • 您的 call(child.children) 使用元素列表(多个子元素)调用闭包,而不是一次调用一个 child
  • 这个例子能不能自成体系,这样我们就可以重现它,那就太好了。
  • 你能在循环外定义和外部化闭包,然后在循环内调用它吗?
  • 推理添加为答案。 :) 我没有看到您在闭包中使用了循环的一部分,但我的建议与我的答案完全相同。

标签: groovy closures


【解决方案1】:

您可以替换dmahapatro's correct answer中的多个for循环:

for(int i=0; i < elementsToGetID.size(); i++){
    for(int j=0; j < jsonArray.size(); j++){
        def closure //defined locally

        closure = { element ->
            if(element.name == elementsToGetID[i].value){
                elementsToGetID[i]["id"] = element.id
            }
            if (element.children) {
                element.children.each {inst ->
                    closure(inst) //This call does not fail anymore
                }
            }
        }

        closure(jsonArray[j])
    }
}

这样,得到相同的结果:

jsonArray.each { a ->
    elementsToGetID.find { a.name == it.value }?.id = a.id
    if( a.children ) {
        { -> a.children.each( owner ) }()
    }
}

【讨论】:

  • 看起来很整洁!会试一试。谢谢!
  • +1 太好了。对于 OP:(如果您想知道 owner 是什么):owner 是用于递归的匿名闭包的直接父闭包。在这种情况下,它是each 中使用的闭包。 @Armand
【解决方案2】:

这就是好处。有用。 :)

原因
对于递归,闭包必须在调用之前了解它自己。

def json = '''
[
    {
        "id": "1",
        "name": "No Children"
    },
    {
        "id": "2",
        "name": "Does not like Children either"
    },
    {
        "id": "123",
        "name": "Some Parent Element",
        "children": [
            {
                "id": "123123",
                "name": "NameWhatever"
            },
            {
                "id": "123123123",
                "name": "Element with Additional Children",
                "children": [
                    {
                        "id": "123123123",
                        "name": "WhateverChildName"
                    },
                    {
                        "id": "12112",
                        "name": "NameToMap"
                    }
                ]
            }
        ]
    }
]
'''

def jsonArray = new groovy.json.JsonSlurper().parseText(json)
def elementsToGetID = [["count": 2741,"value": "NameToMap" ], 
                       ["count": 133,"value": "OtherName" ]]

//can be defined here as well
//def closure

for(int i=0; i < elementsToGetID.size(); i++){
    for(int j=0; j < jsonArray.size(); j++){
        def closure //defined locally

        closure = { element ->
            if(element.name == elementsToGetID[i].value){
                elementsToGetID[i]["id"] = element.id
            }
            if (element.children) {
                element.children.each {inst ->
                    closure(inst) //This call does not fail anymore
                }
            }
        }

        closure(jsonArray[j])
    }
}

assert elementsToGetID == [[count:2741, value:'NameToMap', id:'12112'], 
                           [count:133, value:'OtherName']]

【讨论】:

    猜你喜欢
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多