What is this Groovy construct do, and how does the syntax work?
Asked Answered
G

2

8

I ran into something strange when doing some data-driven testing in Groovy. If it matters, this is inside a Spock test.

Here is the way, I think, that lists are supposed to work:

    def list = [[1, 2, 3],
                [4, 5, 6],
                [7, 8, 9]]

    println list[0]

produces:

[1, 2, 3]

I accidentally did something like this:

    def whut = [[1, 2, 3]
                [4, 5, 6]
                [7, 8, 9]]

    println whut[0]
    println whut

which outputs:

[null, null, null]
[[null, null, null]]

OK, I can see that Groovy did not like the declaration without the commas - but it compiles, so what is this?

Here's what really throws me about this syntax:

    def inputz = [
            [1, 0.631226308, 0.631226308, 0.631226308, 1, 0, 0.240426243]
            [1, 0.312284518, 0.312284518, 0.312284518, 1, 1, 1          ]
            [3, 0.823506476, 0.31230335,  0.631237191, 1, 1, 0          ]
            [4, 0.934875788, 0.486395986, 0.66732053,  3, 2, 0.927654169]
            [4, 0.699869773, 0.234328294, 0.424739329, 3, 3, 1          ]
    ]

    println inputz[0]
    println inputz

yields the following:

[0.631226308, 1, 1, 1, 1, 1, 1]
[[0.631226308, 1, 1, 1, 1, 1, 1]]

I'm completely lost here - what is the Groovy construct I'm creating, and why does it output these seemingly random values from my lists?

Thanks, and if you think of a more descriptive name for my question, I'll change it.

Gnathion answered 8/4, 2015 at 17:44 Comment(1)
We used this awesome question as a puzzler in the second season of the #groovypuzzlers and want to send you a thank-you t-shirt. How can I reach you?Litta
A
10

So

def whut = [[1, 2, 3]
            [4, 5, 6]
            [7, 8, 9]]

Creates a list [1,2,3], accesses the elements 4, 5 and 6 (which don't exist) to give you a list of three nulls, then accesses element 7,8 and 9 of this list of nulls (again three nulls are returned)

It then wraps this list of three nulls in a list

With this example:

[1, 0.631226308, 0.631226308, 0.631226308, 1, 0, 0.240426243]
[1, 0.312284518, 0.312284518, 0.312284518, 1, 1, 1          ]
....

it drills down to:

[1, 0.631226308, 0.631226308, 0.631226308, 1, 0, 0.240426243]
[1, 0, 0, 0, 1, 1, 1]

To give the 1st, 0th, 0th, 0th, 1st, 1st and 1st and ends up with

[0.631226308, 1, 1, 1, 0.631226308, 0.631226308, 0.631226308]

so on and so forth.

Absenteeism answered 8/4, 2015 at 18:1 Comment(1)
That would have been so much more apparent had I not been working on a 0-1 probability issue. Thanks for your well-written explanation.Gnathion
K
6

Breaking this down into a smaller example (in groovysh):

> [[1,2][3,4]]
===> [[null, null]]

But we don't need the extra array, so we can unwrap this:

> [1,2][3,4]
===> [null, null]

This is actually a kind of list indexing, which normally looks like this:

> [1,2][1]
===> 2

But if we index off the end of the array:

> [1,2][2]
===> null

It turns out, groovy supports slicing as part of this syntax (see http://groovy-lang.org/groovy-dev-kit.html#Collections-Slicingwiththesubscriptoperator for more examples), so we can do:

> [1,2,3][2,0]
===> [3, 1]

To get the 3rd element followed by the first element.

But combining these two facts:

> [1,2][3,4]
===> [null, null]

We're indexing past the end of the array again, but with a slice, giving us two nulls.

Kho answered 8/4, 2015 at 18:1 Comment(1)
2 great answers, wish I could check both!Gnathion

© 2022 - 2024 — McMap. All rights reserved.