Reputation: 3669
I am attempting to write a mini recursive closure to solve a parent children iteration. At a certain moment I need check if other children exists before I recursively call the closure. I do the check with an IF but for some reason the if returns always true.
Updating the code with the objects that are included
Have an Json object which has the structure Parent Children (referred as jsonArray in the code below)
[
{
"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"
}
]
}
]
}
]
There is also an ArrayList object which has no IDs and need to retrieve them from the iteration in the jsonArray, This is referred to as elementsToGetID which I am oversimplifying:
["count": 2741,"value": "NameToMap" ], ["count": 133,"value": "OtherName" ]
Thetwo for loops have been written time ago, and I am trying to write the recursive closure to go deeper into the children
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])
}
}
Upvotes: 3
Views: 8555
Reputation: 171194
You can replace the multiple for
loops in dmahapatro's correct answer:
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])
}
}
with this, to get the same result:
jsonArray.each { a ->
elementsToGetID.find { a.name == it.value }?.id = a.id
if( a.children ) {
{ -> a.children.each( owner ) }()
}
}
Upvotes: 3
Reputation: 50285
This is the benefit. It works. :)
Reason
For recursion, a closure has to understand itself that it is defined before it is invoked.
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']]
Upvotes: 2