Reputation: 948
I'm trying to get the first K elements from a sorted map by the following piece of code:
//return top rank k elements
public static LinkedHashMap<String,Double> getTopRank(int i){
//store top k elements
LinkedHashMap<String, Double> result=new LinkedHashMap<>();
int count=0;
//use the static rankMap in the class
rankMap.each {key,value->
result.put(key, value);
count++;
if(count>=i){
println "Time to return"
return result;
}
}
//in case the loop does not work
return result;
}
What I expect is that when the result Map already has a size of i elements, the method will return, giving me a i-size sorted map. Note that rankMap
stores the elements in a certain order I want, and its size is far bigger than int i I pass to the method.
And I'm calling the method by
LinkedHashMap<String,Double> content=getTopRank(outputSize);
But unexpectedly finally the content had the size of rankMap
rather than i
! And in the console I saw hundreds of Time to return
lines. The line return result
was executed again and again until it reached the end of rankMap
.
I'm pretty sure that the line getTopRank(outputSize)
was not in a loop. Then it seems strange to me why this method can return multiple times without ending. Is it caused by my putting return
statement in the closure?
Please advise or tell me how this is true in Groovy. One step further, how can I get only first k elements from a sorted map then?
Upvotes: 5
Views: 2701
Reputation: 513
public static LinkedHashMap<String,Double> getTopRank(int i){
rankMap.take(i)
}
http://www.groovy-lang.org/gdk.html
http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Map.html#take(int)
Upvotes: 0
Reputation: 14539
The method itself is not returning. each
is a method which receives a closure. Closures have their own returning context, which is not tied to the method who invoked them, thus, the loop is not broken.
I'd like to suggest getting a range from the map's entrySet
and collecting the resulting entries:
def getTopRank(int i) {
rankMap
.entrySet()
.toList()[0..<i]
.collectEntries()
}
rankMap = [
'Beatles' : 'The White Album',
'Pink Floyd' : 'The Dark Side of the Moon',
'Rolling Stones' : 'Sticky Fingers',
'The Doors' : 'Morrison Hotel',
'Bob Dylan' : 'Bob Dylan'
]
assert getTopRank(2) == [
'Beatles' : 'The White Album',
'Pink Floyd' : 'The Dark Side of the Moon']
assert getTopRank(4) == [
'Beatles' : 'The White Album',
'Pink Floyd' : 'The Dark Side of the Moon',
'Rolling Stones' : 'Sticky Fingers',
'The Doors' : 'Morrison Hotel',]
Upvotes: 2
Reputation: 20709
You misunderstood key concepts of Groovy.
The only way to finish the each()
execution before reaching the end, is to throw an exception. If your want to exit the loop conditionally, use standard loop types like for
or while
:
int count=0
def result = [:]
for( def e in rankMap ){
count++
result[ e.key ] = e.value
if( i <= count ) return result
}
Upvotes: 4