如何计算scala中的学生成绩排名?

时间:2018-03-15 17:27:02

标签: scala rank

在我的问题中,每个学生都有一个班级,每个科目都有一个每个学生的分数。 现在我想让所有学生在学校排名,在课堂上为每个科目和总分排名。 学生分数数据如下:

userName class subject score
Mike     1     math    100
Jack     1     math    100
Jone     1     math    90
Helan    2     math    95
Mike     1     physics 100

,预期结果是

userName  mathRank mathRank(class) physicsRank physicsRank(class) sumRank sumRank(class)
Mike      1        1               1           1                   1  1
Jack      1        1       
John      4        3       
Hellan    3        1       

我写了一些代码,我的代码在下面

  case class UserScore(userName:String,stuClass:Int,subject:String,score:Double)
  val userScores :Array[UserScore] = Array[UserScore](
  UserScore("Mike", 1, "math", 100D),
  UserScore("Jack", 1, "math", 100D),
  UserScore("Jone", 1, "math", 90D),
  UserScore("Helan", 2, "math", 95D),
  UserScore("Mike", 1, "physics", 95D))
//calculate school rank
  val subjectID2SchoolRanks = userScores.sortBy(_.score).reverse.groupBy(_.subject).map({
  case(subjectID, subjectUserScores)=>{
    var i:Int = 0
    subjectID->subjectUserScores.foldLeft(List[(UserScore,Int)]()){
      (userScoreRanks,userScore)=>{
         i= i+1
         if(userScoreRanks.nonEmpty&& userScoreRanks.last._1.score==userScore.score){
           userScoreRanks:+(userScore,userScoreRanks.last._2)
         }else {
           userScoreRanks:+(userScore,i)
         }
      }
    }
  }
})

但也许效率低而且不优雅,任何人都可以给我一些建议,提前谢谢。

1 个答案:

答案 0 :(得分:1)

此代码与您的结果相同,但不使用可变变量。

val subjectID2SchoolRanks = 
    userScores.groupBy(_.subject)
              .mapValues(_.sortWith(_.score >= _.score)
                          .zipWithIndex
                          .foldLeft((List[(UserScore,Int)](),-1.0,-1)){
                            case ((acc,pScore,pRank),(us,rank)) =>
                              if (pScore == us.score)
                                ((us,pRank)::acc, pScore, pRank)
                              else
                                ((us,rank+1)::acc, us.score, rank+1)
                          }._1.reverse)

我使用了许多相同的步骤,但并不总是以相同的顺序。 zipWithIndex用于确定初始排名,然后foldLeft进行必要的调整。附加到List是一种效率相当低的操作。通过预先挂起List然后reverse构建c_infos通常会更好。