I want to perform a copy and get two different objects so that I can work on the copy without impacting the original.
I have this code (groovy 2.0.5):
def a = [[1,5,2,1,1], ["one", "five", "two", "one", "one"]]
def b = a
b.add([6,6,6,6,6,6])
println a
println b
that produces:
[[1, 5, 2, 1, 1], [one, five, two, one, one], [6, 6, 6, 6, 6, 6]]
[[1, 5, 2, 1, 1], [one, five, two, one, one], [6, 6, 6, 6, 6, 6]]
seems like b and a are actually the same object
I can fix it in this way:
def a = [[1,5,2,1,1], ["one", "five", "two", "one", "one"]]
def b = []
a.each {
b.add(it)
}
b.add([6,6,6,6,6])
println a
println b
that produces my wanted result:
[[1, 5, 2, 1, 1], [one, five, two, one, one]]
[[1, 5, 2, 1, 1], [one, five, two, one, one], [6, 6, 6, 6, 6]]
But now look at this, where I want the original object and a copy with unique and sorted elements:
def a = [[1,5,2,1,1], ["one", "five", "two", "one", "one"]]
def b = a
b.each {
it.unique().sort()
}
println a
println b
that produces:
[[1, 2, 5], [five, one, two]]
[[1, 2, 5], [five, one, two]]
If I try the same fix this time it doesn't work:
def a = [[1,5,2,1,1], ["one", "five", "two", "one", "one"]]
def b = []
a.each {
b.add(it)
}
b.each {
it.unique().sort()
}
println a
println b
that still produces:
[[1, 2, 5], [five, one, two]]
[[1, 2, 5], [five, one, two]]
What's going on ?
Just calling b = a
sets b
to being the same instance of the list (containing the same list instances) as a
Calling the second method with the a.each { b.add(it) }
means b points to a different instance of List, but the contents of b
are the same instances of lists as in a
What you need is something like:
def b = a*.collect()
b.each {
it.unique().sort()
}
So the a*.collect()
makes a new instance of a list for each list in a
You can also do this in one line:
def b = a*.unique( false )*.sort( false )
Passing false
to unique
and sort
stop those method changing the original lists, and force them to return new list instances.
(Indeed the observant amongst you will notice that the sort
does not need false
passed to it, as we already have a new instance thanks to unique
)
Groovy has Collection#collectNested
, which is the recursive form of #collect
. This will create copies of lists of arbitrary depth. Prior to version 1.8.1 it's called #collectAll
.
final a = [
'a', [ 'aa', 'ab', [ 'aba', 'abb', 'abc' ], 'ac', 'ad' ], 'b', 'c', 'd', 'e'
]
final b = a.collectNested { it }
b[0] = 'B'
final c = a.collectNested { it * 2 }
c[0] = 'C'
assert a as String ==
'[a, [aa, ab, [aba, abb, abc], ac, ad], b, c, d, e]'
assert b as String ==
'[B, [aa, ab, [aba, abb, abc], ac, ad], b, c, d, e]'
assert c as String ==
'[C, [aaaa, abab, [abaaba, abbabb, abcabc], acac, adad], bb, cc, dd, ee]'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With