Reputation: 286
I have a short groovy algorithm for assigning rankings to food based on their rating. This can be run in the groovy console. The code works perfectly, but I'm wondering if there is a more Groovy or functional way of writing the code. Thinking it would be nice to get rid of the previousItem
and rank
local variables if possible.
def food = [
[name:'Chocolate Brownie',rating:5.5, rank:null],
[name:'Fudge', rating:2.1, rank:null],
[name:'Pizza',rating:3.4, rank:null],
[name:'Icecream', rating:2.1, rank:null],
[name:'Cabbage', rating:1.4, rank:null]]
food.sort { -it.rating }
def previousItem = food[0]
def rank = 1
previousItem.rank = rank
food.each { item ->
if (item.rating == previousItem.rating) {
item.rank = previousItem.rank
} else {
item.rank = rank
}
previousItem = item
rank++
}
assert food[0].rank == 1
assert food[1].rank == 2
assert food[2].rank == 3
assert food[3].rank == 3 // Note same rating = same rank
assert food[4].rank == 5 // Note, 4 skipped as we have two at rank 3
Suggestions?
Upvotes: 1
Views: 1303
Reputation: 26801
Here's another alternative that doesn't use "local defs" with the groovy inject method:
food.sort { -it.rating }.inject([index: 0]) { map, current ->
current.rank = (current.rating == map.lastRating ? map.lastRank : map.index + 1)
[ lastRating: current.rating, lastRank: current.rank, index: map.index + 1 ]
}
Upvotes: 0
Reputation: 8078
This is my solution:
def rank = 1
def groupedByRating = food.groupBy { -it.rating }
groupedByRating.sort().each { rating, items ->
items.each { it.rank = rank }
rank += items.size()
}
Upvotes: 2
Reputation: 2850
I didn't try it, but maybe this could work.
food.eachWithIndex { item, i ->
if( i>0 && food[i-1].rating == item.rating )
item.rank = food[i-1].rank
else
item.rank = i + 1
}
Upvotes: 0