Решение проблемы ранжирования чисто функциональным способом с использованием Groovy - PullRequest
0 голосов
/ 01 февраля 2019

Я решил проблему, которая ранжирует фрукты по количеству голосов.К сожалению, я хочу решить проблему чисто функциональным способом без изменения переменной 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"

Тогда я, любой, мог бы оценить ваше решение или просто предположить, что моя попытка является наиболее реалистичным способомрешая это.

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Я, вероятно, не очень хорошо объяснил, чего я пытался достичь.После вычисления ранга я хотел, чтобы значения были вставлены для соответствующих элементов в списке.Вот что я придумал:

  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"

Окончательный результат выглядит как отсортированные фрукты: [[name: лимоны, голосов: 20, рейтинг: 1], [имя: гуавы, голосов: 20, рейтинг: 1], [имя: ананас, голосов: 50, рейтинг: 3], [имя: абрикос, голосов: 66, рейтинг: 4], [имя: слива, голосов: 66, рейтинг: 4] и т. Д.

0 голосов
/ 08 февраля 2019

Это чисто функциональное решение.Он оставляет исходную карту без изменений и создает новую:

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]
0 голосов
/ 03 февраля 2019

Вы можете попробовать это:

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()
})

Но оба решения на самом деле не работают.Реальный функциональный код обрабатывает все значения, как если бы они были неизменяемыми.Смотрите мой другой ответ (в ближайшее время) для реального функционального решения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...