Skip to content

Instantly share code, notes, and snippets.

@timyates
Created April 24, 2012 09:33
Show Gist options
  • Save timyates/2478326 to your computer and use it in GitHub Desktop.
Save timyates/2478326 to your computer and use it in GitHub Desktop.
A two-line tree in Groovy

Two line Tree in Groovy


Update!

Wow... Kiyotaka Oku's fork of this shows how to do it in one line :-)


The other day, I saw Harold Cooper's One-line tree in Python via autovivication, and wondered if the same thing was possible in Groovy.

The answer is yes! But you need to define the variable tree before you can assign it to the self-referential withDefault closure, hence with Groovy, it's a two-line solution ;-)

Anyway, given:

def tree
tree = { -> return [:].withDefault{ tree() } }

We can then do:

users = tree()
users.harold.username = 'hrldcpr'
users.yates.username = 'tim'

And printing this out

println new groovy.json.JsonBuilder( users ).toPrettyString()

gives:

{
    "harold": {
        "username": "hrldcpr"
    },
    "yates": {
        "username": "tim"
    }
}
@hrhristov
Copy link

Is it possible to load "users" from String as well?

@timyates
Copy link
Author

@hrhristov Yeah, given:

def tree = { [:].withDefault{ owner.call() } }

And some JSON representing Users:

def json = '''{
             |   "harold": {
             |        "username": "hrldcpr"
             |    },
             |    "yates": {
             |        "username": "tim"
             |    }
             |}'''.stripMargin()

Then we can read it into a Map using:

def users = new groovy.json.JsonSlurper().parseText( json )

However, if we want to add new branches automatically to this as if it were a tree (as above), then we need something to take a map and decorate all the "branches" as trees

def mapToTree = { map -> map.inject( tree() ) { m, n ->
    m << [ (n.key):n.value instanceof Map ? owner.call( n.value ) : n.value ]
  }
}

Then, we can get the users like so:

def users = mapToTree( new groovy.json.JsonSlurper().parseText( json ) )

And add to it as before:

users.bert.username = 'woo'
println new groovy.json.JsonBuilder( users ).toPrettyString()

which now prints:

{
    "harold": {
        "username": "hrldcpr"
    },
    "yates": {
        "username": "tim"
    },
    "bert": {
        "username": "woo"
    }
}

Hope this helps :-)

@hrhristov
Copy link

Awesome! Thanks! :)

@antsmartian
Copy link

@timyates The above solution is also Groovi-er ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment