我解决了一个根据票数对水果进行排名的问题。不幸的是,我想以一种纯粹的功能性方式解决该问题,而无需更改rankPosition变量。这是我的解决方案:
def fruits=[
[name:'apple', votes:120 , ranking:null ],
[name:'banana', votes:200, ranking: null],
[name:'apricot', votes:66, ranking:null ],
[name:'pear', votes:84, ranking:null],
[name:'kiwi', votes:77, ranking:null],
[name:'plum', votes:66, ranking:null],
[name:'berry', votes:120, ranking:null],
[name:'pineapple', votes:50, ranking:null],
[name:'grapes', votes:200, ranking:null]
]
def rankPosition= 1
def groupedByVotes = fruits.groupBy {it.votes }
println "Ratings $groupedByVotes"
def finalResults=groupedByVotes.sort().each { votes, items ->
items.each { it.ranking = rankPosition }
rankPosition += items.size()
}
println "Final Results are $finalResults"
我如何解决此问题而不必在闭包外部声明rankingPosition变量并更改其状态。请注意,此解决方案有效,但是自那以后,我了解到我不应该这样做。 我希望能够用正确的排名来填充排名。注入函数会进行累加,但是我不知道如何以某种方式将其组合起来,从而也可以使用注入中累积的值来设置排名。
我只是被困住了,只是似乎无法对此做出推理。我在下面尝试使用注入的尝试根本没有用。也许没有办法以纯粹的功能方式做到这一点,更好的是我的尝试。
def res= groupedByVotes.collectEntries{votes, list1->
println "list class $list1"
def r= list1.inject(0){acc,l-> acc+l.size()}
list1.each{it.ranking=r}
println "$r"
[(votes): list1]
}
println "$res"
那么我每个人都可以感谢您的解决方案,或者只是假设我的尝试是解决这一问题的最现实的方法。
答案 0 :(得分:0)
您可以尝试以下方法:
def results = groupedByVotes.sort()
.inject(new Tuple(1, []), { acc, entry ->
entry.value.each { it.ranking = acc[0] }
return new Tuple(acc[0] + entry.value.size(), acc[1] << entry.value)
})
finalResults = results[1]
在折叠的每个步骤(由.inject(...)
完成)中,您都有一个Tuple
,其中包含下一排和到目前为止已计算的部分列表。最后一步是从Tuple
中提取结果列表。但这会将地图转换为列表。
此解决方案甚至更简单,因为如果就地修改了旧集合,则不必创建新集合,并且可以保留地图:
def finalResults = groupedByVotes.sort()
finalResults.inject(1, { acc, entry ->
entry.value.each { it.ranking = acc }
return acc + entry.value.size()
})
但是这两种解决方案都没有真正起作用。实际的功能代码将所有值视为不变。请参阅我的其他答案(即将推出)以获取真正的功能解决方案。
答案 1 :(得分:0)
我可能没有很好地解释我要达到的目标。在计算排名之后,我希望为列表中的各个元素插入值。这是我想出的:
def sortedFruits= fruits.sort{f1, f2 -> f1.votes <=> f2.votes}
(0..sortedFruits.size()-1)
.each{ i ->
if(i==0){
sortedFruits.get(i).ranking=1
}else if(sortedFruits.get(i-1).votes==sortedFruits.get(i).votes){
sortedFruits.get(i).ranking=i
}else{
sortedFruits.get(i).ranking=i+1
}
if(i<sortedFruits.size()){
def f= sortedFruits.get(i)
println "${f}"
}
}
println "Sorted Fruits are $sortedFruits"
最终结果看起来像 排序的水果是[[名称:柠檬,投票:20,排名:1],[名称:番石榴,投票:20,排名:1], [名称:菠萝,投票:50,排名:3],[名称:杏,投票:66,排名:4],[ 名称:李子,投票数:66,排名:4]等。
答案 2 :(得分:0)
这是一个纯功能解决方案。它将原始地图的地图保持不变,并生成一个新的地图:
def results = groupedByVotes.sort().inject(new Tuple(1, [:]), { acc, entry ->
def newRank = acc[0] + entry.value.size()
def newValue = entry.value.collect { [*:it, ranking:acc[0]] }
return new Tuple(newRank, [*:acc[1], (entry.key):newValue] )
})
finalResults = results[1]