在我的问题中,每个学生都有一个班级,每个科目都有一个每个学生的分数。 现在我想让所有学生在学校排名,在课堂上为每个科目和总分排名。 学生分数数据如下:
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)
}
}
}
}
})
但也许效率低而且不优雅,任何人都可以给我一些建议,提前谢谢。
答案 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
通常会更好。