任务描述
本关任务:本关主题是利用Scala函数式编程中已经实现的排序函数实现相关的排序需求。在一次考试中,Cathy、Daniel和Andy的成绩如下:
| 科目 | 语文 | 数学 | 英语 | 物理 | 化学 | 生物 |
| Cathy | 100 | 110 | 108 | 78 | 95 | 89 |
| Daniel | 110 | 98 | 110 | 80 | 94 | 88 |
| Andy | 105 | 120 | 115 | 85 | 90 | 95 |
试给这三位同学进行排名,排名规则:按总分降序排序,若总分相同,则按语数英三门总分降序排序;若三门总分仍然相同,则按姓名升序排序。请仔细阅读下面“相关知识”中的内容,理解排序的各种操作,补全代码中的内容,使得程序运行结果如预期输出。
相关知识
排序方法在实际的应用场景中非常常见,Scala里面有三种排序方法,分别是: sorted,sortBy ,sortWith。
(1)sorted
对一个集合进行自然排序,通过传递隐式的Ordering。
(2)sortBy
对一个属性或多个属性进行排序,通过它的类型。
(3)sortWith
基于函数的排序,通过一个comparator函数,实现自定义排序的逻辑。
基于单集合单字段的排序
object TestSort_01{ def main(args:Array[String]){ val xs=Seq(1,5,3,4,6,2) println("==============sorted排序=================") println(xs.sorted) //升序 println(xs.sorted.reverse) //降序 println("==============sortBy排序=================") println( xs.sortBy(d=>d) ) //升序 println( xs.sortBy(d=>d).reverse ) //降序 println("==============sortWith排序=================") println( xs.sortWith(_<_) )//升序 println( xs.sortWith(_>_) )//降序 } }
结果:
==============sorted排序=================
List(1, 2, 3, 4, 5, 6, 7, 8, 9)
List(9, 8, 7, 6, 5, 4, 3, 2, 1)
==============sortBy排序=================
List(1, 2, 3, 4, 5, 6, 7, 8, 9)
List(9, 8, 7, 6, 5, 4, 3, 2, 1)
==============sortWith排序=================
List(1, 2, 3, 4, 5, 6, 7, 8, 9)
List(9, 8, 7, 6, 5, 4, 3, 2, 1)
基于元组多字段的排序
多字段的排序,使用sorted比较麻烦,一般使用sortBy和sortWith。
(1)基于sortBy的实现:
object TestSort_02{ def main(args:Array[String]){ val pairs = Array( ("a", 5, 1), ("c", 3, 1), ("b", 1, 3) ) //按第三个字段升序,第一个字段降序,注意,排序的字段必须和后面的tuple对应 val bx= pairs.sortBy(r => (r._3, r._1))( Ordering.Tuple2(Ordering.Int, Ordering.String.reverse) ) //打印结果 bx.map( println ) } }
结果:
(c,3,1)
(a,5,1)
(b,1,3)
(2)基于sortWith的实现:
object TestSort_03{ def main(args:Array[String]){ val pairs = Array( ("a", 5, 1), ("c", 3, 1), ("b", 1, 3) ) val b= pairs.sortWith{ case (a,b)=>{ if(a._3==b._3) {//如果第三个字段相等,就按第一个字段降序 a._1>b._1 }else{ a._3<b._3 //否则第三个字段降序 } } } //打印结果 b.map(println) } }
结果:
(c,3,1)
(a,5,1)
(b,1,3)
可以看出,基于sortBy的实现比较优雅,语义比较清晰,基于sortWith的灵活性更强,但代码稍加繁琐。
基于类的排序
(1)sortBy的实现方法
排序规则:先按年龄排序,如果一样,就按照名称降序排。
object TestSort_04{ def main(args:Array[String]){ case class Person(val name:String,val age:Int) val p1=Person("cathy",23) val p2=Person("daniel",23) val p3=Person("andy",25) val pairs = Array(p1,p2,p3) //先按年龄排序,如果一样,就按照名称降序排 val bx= pairs.sortBy(person =>(person.age, person.name)) ( Ordering.Tuple2(Ordering.Int, Ordering.String.reverse) ) bx.map(println) } }
结果:
Person(daniel,23)
Person(cathy,23)
Person(andy,25)
(2)sortWith的实现方法
排序规则:年龄一样,按名字降序排,否则按年龄升序排。
object TestSort_05{ def main(args:Array[String]){ case class Person(val name:String,val age:Int) val p1=Person("cathy",23) val p2=Person("daniel",23) val p3=Person("andy",25) val pairs = Array(p1,p2,p3) val b=pairs.sortWith{ case (person1,person2)=>{ person1.age==person2.age match { //年龄一样,按名字降序排 case true=> person1.name > person2.name case false=>person1.age < person2.age //否则按年龄升序排 } } } b.map(println) } }
结果:
Person(daniel,23)
Person(cathy,23)
Person(andy,25)
总结:
本关介绍了scala里面的三种排序函数,都有其各自的应用场景:
(1)sorted:适合单集合的升降序。
(2)sortBy:适合对单个或多个属性的排序,代码量比较少,推荐使用这种。
(3)sortWith:适合定制化场景比较高的排序规则,比较灵活,也能支持单个或多个属性的排序,但代码量稍多,内部实际是通过java里面的Comparator接口来完成排序。
实际应用中,可以根据具体的场景来选择合适的排序策略。
编程要求
补全代码中的内容,以使得程序运行结果如预期输出。具体请参见后续测试样例。
测试说明
平台会对你编写的代码进行测试:
测试输入:无输入;
预期输出:
(Andy,340,610)
(Cathy,318,580)
(Daniel,318,580)
object TestSort{ def main(args:Array[String]){ val pairs = Array( ("Cathy", 100, 110, 108, 78, 95, 89), ("Daniel", 110, 98, 110, 80, 94, 88), ("Andy", 105, 120, 115, 85, 90, 95) ) //**************Begin************************* //构造新数组(姓名,三科总分,六科总分) val count = Array( (pairs{0}._1,pairs{0}._2+pairs{0}._3+pairs{0}._4, pairs{0}._2+pairs{0}._3+pairs{0}._4+pairs{0}._5+pairs{0}._6+pairs{0}._7), (pairs{1}._1,pairs{1}._2+pairs{1}._3+pairs{1}._4, pairs{1}._2+pairs{1}._3+pairs{1}._4+pairs{1}._5+pairs{1}._6+pairs{1}._7), (pairs{2}._1,pairs{2}._2+pairs{2}._3+pairs{2}._4, pairs{2}._2+pairs{2}._3+pairs{2}._4+pairs{2}._5+pairs{2}._6+pairs{2}._7) ) //排序 val b= count.sortWith{ case (a,b)=>{ if(a._3==b._3) {//如果总分相等,就按三科降序 if(a._2==b._2) a._1<b._1 else a._2>b._2 }else { a._3>b._3 //否则总分降序 } } } //**************End************************** //打印结果 b.map(println) } }