如何计算scala中的学生成绩排名?
How to calculate student score rank in scala?
在我的问题中,每个学生都有一个 class,每个科目都有每个学生的分数。
现在我想获得所有学生在学校的排名,每个科目和总分的排名 class。
学生成绩数据是这样的:
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)
}
}
}
}
})
但可能效率不高也不优雅,谁能给我一些建议,在此先感谢。
这段代码得到的结果与你的相同,但没有使用可变变量。
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
是一个相当低效的操作。通常最好通过 pre-pending 为它构建 List
,然后在构建之后 reverse
。
在我的问题中,每个学生都有一个 class,每个科目都有每个学生的分数。 现在我想获得所有学生在学校的排名,每个科目和总分的排名 class。 学生成绩数据是这样的:
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)
}
}
}
}
})
但可能效率不高也不优雅,谁能给我一些建议,在此先感谢。
这段代码得到的结果与你的相同,但没有使用可变变量。
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
是一个相当低效的操作。通常最好通过 pre-pending 为它构建 List
,然后在构建之后 reverse
。