How does Groovy handle closure scope and recursion? - groovy

I have a recursive Python function that builds a tree, and I'm trying to translate it into Groovy.
Here's the Python version...
def get_tree(vertices):
results = []
if type(vertices) != list:
vertices = [vertices]
for vertex in vertices:
results.append(vertex)
children = get_children(vertex)
if children:
child_tree = get_tree(children)
results.append(child_tree)
return results
Here's the output of get_tree(1)...
[1, [2, 3, 4, [5, 3]]]
And here's my attempt to translate this into a Groovy closure...
_tree = { vertices ->
results = []
vertices.each() {
results << it
children = it."$direction"().toList()
if (children) {
child_tree = _tree(children)
results << child_tree
}
}
results
}
But this doesn't work -- this is what it returns...
gremlin> g.v(1).outTree()
==>[v[5], v[3], (this Collection), (this Collection)]
What are those "this Collection"s about?
I have only a cursory understanding of Groovy, and I suspect it's something to do with how Groovy handles recursion and closure scope.
Please enlighten me :)

The solution was to add def to results = []:
_tree = { vertices ->
def results = []
vertices.each() {
results << it
children = it."$direction"().toList()
if (children) {
child_tree = _tree(children)
results << child_tree
}
}
results
}
See https://groups.google.com/d/msg/gremlin-users/iCPUifiU_wk/mrUhsjOM2h0J

Related

Find bit location in groovy and put into an list

The groovy script needs to find the x location of string1 and put them into a list. The final output will be like
finaList=[[2,3],[5]]
The following scripts are created by me, but it doesn't work
checkStr='01xx0x1'
i=0
tempaList=[]
finalList=[]
while (i<checkStr.length()){
if(checkStr[i]=='x'){
tempaList.add(i)
}else if(tempaList.length()>1){
finalList.add([tempaList[0],tempaList[-1]])
tempaList=[]
}else if (tempaList.length()==1){
finaList.add([tempaList])
tempaList=[]
}
i=i+1
}
println finaList
I'm a bit confused by your desired result of a list of lists. If, as you stated, your only goal is to find all indexes that 'x' is at, you can use:
def str ='01xx0x'
str.findIndexValues { it == 'x' } // result -> [2, 3, 5]
If you do want to maintain your groupings, you need to make sure you handle the case of your last character being an 'x'. Your current code will not handle instances where tempaList has a value but the loop has finished iterating over the string.
def checkStr = '01xx0x1'
def temp = []
def end = []
for (int i=0; i < checkStr.size(); i++) {
if (checkStr[i] == 'x') {
temp << i
} else if (temp.size()) {
// temp has size (indexes) and we've hit a non-'x' char
end << temp
temp = []
}
}
// If the final char was an x (or multiple x's), handle that here
if (temp) {
end << temp
}
println end // result -> [[2, 3], [5]]
checkStr='01xx0x1'
i=0
tempaList=[]
finalList=[]
while(i<checkStr.length()){
if(checkStr[i]=="x"){
// println i
tempaList.add(i)
}else if (tempaList.size()>1){
finalList.add([tempaList[0],tempaList[-1]])
tempaList=[]
}else if (tempaList.size()==1){
finalList.add(tempaList)
tempaList=[]
}
i=i+1
}
println finalList

groovy map populate with default element

Is there more Groovish way of adding an element to map of lists and initialize default list if not exists?
Or in other words what would be a Groovish way to code the below:
def mylist = [1,2,3,4]
def mymap = [:]
for (num in mylist){
if (num % 2 == 0){
pairity = "even"
} else {
pairity = "odd"
}
if (mymap.containsKey(pairity)){
println("Adding to Even")
mymap[pairity].add(num)
}
else {
println("adding to Odd")
mymap[pairity] = [num]
}
}
print(mymap.toString())
// adding to Odd
// adding to Odd
// Adding to Even
// Adding to Even
// [odd:[1, 3], even:[2, 4]]
You can use withDefault on a map to have automatically generate a value for a missing key on access.
[1,2,3,4].inject([:].withDefault{[]}){ m, i -> m[ i%2==0 ? 'odd' : 'even' ] << i; m }
// => [even:[1, 3], odd:[2, 4]]
You can simply groupby:
def mymap = mylist.groupBy { it % 2 == 0 ? 'even' : 'odd' }
That is effectively using the closure to partition the list on the condition.

Groovy: Get index of all occurences of sublist from arraylist

I am new to groovy and trying to find the indexes of all sublists in a list.
I am trying to use something like Collections.indexOfSubList like in java but it gives exception saying it applies on Lists and not ArrayLists.
So I am trying to define my own function. I am finding all the indices of all the elements in the smaller list existing in the longer list and then subtracting the indices of the result array. If it comes to 1 then I am considering that index to a sublist.
I know that I have the logic a little twisted. Can somebody guide with a better and efficient way of doing this.
Below is my code:
List list1 = [1,2,3,4,5,6,1,2,3]
List list2 = [1,2]
index1 = list1.findIndexValues {
it == list2[0];
}
index2 = list1.findIndexValues {
it == list2[1];
}
println index1
println index2
result = []
for (int i = 0; i < index1.size(); i++) {
result.add(index2[i]-index1[i]);
}
println result
Edit: no longer uses Collections due to new issue re: Elastic Search.
The following code traverses along the source list, creating a sublist. It checks the sublist to see if it starts with the target list. See the asserts below (e.g. the indexes are 0-based):
def listStartsWithSubList = { source, target ->
def result = false
if (source.size() >= target.size()) {
result = true
target.eachWithIndex { item, index ->
result = result && (item == source[index])
}
}
result
}
def indexOfSubLists = { source, target ->
def results = []
source.eachWithIndex { item, index ->
def tmpList = source[index..source.size()-1]
if (listStartsWithSubList(tmpList, target)) {
results << index
}
}
results
}
assert [1] == indexOfSubLists([1,2,3], [2,3])
assert [2] == indexOfSubLists([1,2,3], [3])
assert [] == indexOfSubLists([1,2,3], [4])
assert [0,6] == indexOfSubLists([1,2,3,4,5,6,1,2,3], [1,2])

I need a shorthand way to combine Maps in groovy with slightly different results than +

NOTE: This can be done as a method call or an operator override pretty easily, I am looking for an intrinsic one-line solution that I don't have to carry around in a library.
When you combine(add) Maps, you get a result like this:
println [a:1,c:3] + [a:2]
// prints {a=2, c=3}
I seem to keep needing results more like:
{a=[1, 2], c=[3]}
In other words, something that combines all the values from identical keys in the Maps.
Is there an operator or simple function call that does this, because doing it myself always seems to break my stride a little. It seems like the * operator might do this nicely, but it doesn't.
Is there an easy way to do this?
Another alternative (adding it to the * operator on Maps)
def a = [ a:1, c:10 ]
def b = [ b:1, a:3 ]
Map.metaClass.multiply = { Map other ->
(delegate.keySet() + other.keySet()).inject( [:].withDefault { [] } ) { m, v ->
if (delegate[v] != null) { m[v] << delegate[v] }
if (other[v] != null) { m[v] << other[v] }
m
}
}
assert a * b == [a:[1, 3], c:[10], b:[1]]
Came up with this as well, but it's late and there are probably better, shorter ways
def a = [ a:1, c:10 ]
def b = [ b:1, a:3 ]
[a,b]*.collect {k,v -> [(k):v]}
.flatten()
.groupBy { it.keySet()[0]}
.inject([:].withDefault{[]}) {m,v->
m << [(v.key):v.value[v.key]]
}
​​
Nothing came to my mind, so I start the bidding with this:
m1 = [a:1, c:666]; m2 = [a:2, b:42]
result = [:].withDefault{[]}
[m1,m2].each{ it.each{ result[it.key] << it.value } }
assert result == [a:[1,2], b:[42], c:[666]]

What is the neatest way to remove all but the last item from a list in groovy?

I've been trying to find a neat way to remove all but the last element from a list in groovy, but all the things I've tried seem a bit overcomplicated. Is there a neater way?
FAILS: java.util.ConcurrentModificationException
void removeAllButLastInPlace(list) {
if(list.size() > 1) {
def remove = list[0..-2]
remove.each { list.remove(it) }
}
}
FAILS: java.lang.CloneNotSupportedException: java.util.ArrayList$SubList
void removeAllButLastInPlace(list) {
if(list.size() > 1) {
def remove = list[0..-2].clone()
remove.each { list.remove(it) }
}
}
WORKS, but list construction seems unnecessary
void removeAllButLastInPlace(list) {
if(list.size() > 1) {
def remove = [] + list[0..-2]
remove.each { list.remove(it) }
}
}
WORKS, but seems a bit arcane
void removeAllButLastInPlace(list) {
(list.size() - 1).times { list.remove(0) }
}
WORKS, perhaps most 'correct'
void removeAllButLastInPlace(list) {
list.retainAll { list.lastIndexOf(it) == list.size() - 1 }
}
The code should fulfil the following tests:
list = []
removeAllButLastInPlace(list)
assert list == []
list = ['a']
removeAllButLastInPlace(list)
assert list == ['a']
list = ['a', 'b']
removeAllButLastInPlace(list)
assert list == ['b']
list = ['a', 'b', 'c']
removeAllButLastInPlace(list)
assert list == ['c']
Rather than mutating an existing list., why not return a new list?
Then you can simply do:
List removeAllButLast( List list ) {
list ? [list[-1]] : []
}
Or:
List removeAllButLastInPlace( List list ) {
list.drop( list.size() - 1 )
}
edit:
You could also use a loop (if you have to have a mutating method)
void removeAllButLastInPlace( List list ) {
while( list.size() > 1 ) list.remove( 0 )
}
void removeAllButLastInPlace( List list ) {
def index = 0
list.reverse(true).retainAll({index++ == 0})
}
I'd go for one of these. My criteria being a) modifying the list in place as stated in your requirement (not returning a new list) and b) succinctness.
I have however made both versions return a reference to the modified list just to simplify the println examples. You could make the return type 'void' if preferred and remove the last 'xs' line from each.
def xs1 = [1, 2, 3, 4, 5]
def xs2 = [9]
def xs3 = []
def keepOnlyLast1(xs) {
while(xs.size() > 1) xs.remove(0)
xs
}
def keepOnlyLast2(xs) {
xs[0 ..< xs.size()-1] = []
xs
}
println "Version 1"
println keepOnlyLast1([] + xs1)
println keepOnlyLast1([] + xs2)
println keepOnlyLast1([] + xs3)
println "Version 2"
println keepOnlyLast2([] + xs1)
println keepOnlyLast2([] + xs2)
println keepOnlyLast2([] + xs3)
/* Sanity check that these methods *really* modify the list. */
println "Sanity Check"
keepOnlyLast1(xs1)
println xs1
keepOnlyLast2(xs2)
println xs2
Aside: I would also go for a more functional style if at all possible (i.e. return a new list rather than modifying the existing one) except that that wasn't what you asked for. Here's an example anyway:
def lastAsList(xs) {
xs.isEmpty() ? [] : [xs[-1]]
}
println lastAsList([1, 2, 3])
println lastAsList([])

Resources