美文网首页程序员
scala 排序函数使用和代码分析

scala 排序函数使用和代码分析

作者: 小赵营 | 来源:发表于2019-03-21 19:44 被阅读0次

引用 转载 请注明出处

序列图

scala & java 关系不清,爱者,为止疯狂。怨者,无力吐槽。但在一个方面是无可争议的事实、一个让人趋之若鹜特性 -- scala丰富集合库。

所谓集合库:一种用来存储各种对象和数据的容器,且提供丰富的操作集。本篇我们来介绍scala中集合库常用功能:排序功能。

浏览API我们会发现,排序的功能存在于多个组合库中,那么

  • 它源于哪里?
  • 有哪些具体操作方法?
  • 如何满足我们的排序需求哪?

本文将分别说明,并结合示例分析源码。

操作方法

在API文档中,List Set Map BitSet Option都存在通用的api,在其中有三个接口,满足我们对排序诉求。函数完整签名如下:

//sort api 1 2 3
def sorted[B >: A](implicit ord: Ordering[B]): Repr //1
def sortBy[B](f: A => B)(implicit ord: Ordering[B]): Repr //2
def sortWith(lt: (A, A) => Boolean): Repr //3

api呈现内容:

  • api提供默认排序功能。那么,默认排序是什么哪?

  • api1,2 隐式参数转换是进行排序的基础(关于隐式转换先挖坑,以后写一篇文章),前置提供默认排序方式,后者进行类型转换 A-> B,然后进行排序。2者排序的关键是后面的隐式转换参数 implicit ord: Ordering[B]trait Ordering实现了基本类型的排序方法。

  • api 3 是个似是而非的接口,看似没有Ordering的功能,但实现暴露了本质-- API 1的特殊形式。

    完整实现代码: def sortWith(lt: (A, A) => Boolean): Repr = sorted(Ordering fromLessThan lt)。sortWith是sorted的封装。

来源

排序是scala的集合库提供基础功能。我们在查看基础类继承关系图中,SeqLike总是很特别的一个,我们的排序功能就源于此。为显示方便,UML图中裁剪SeqLike无关函数。

seqlike uml.png

蓝色部分scala提供的排序三剑客SeqLike继承和内部实现类,有兴趣可以分析源码。Uml图源于[我的 github开源uml工具]:scaladiagram 分析scala源码生成UML图,阅读源码事半功倍。

在了解是什么和为什么之后,我们要了解如何用即如何进行排序、以及如何定制化排序?

排序

数据排序无外乎升序,降序和自定义排序。我们使用scala的repl进行操作排序,如下:

  • sorted 使用

scala> List(1,6,4,5).sorted res0: List[Int] = List(1, 4, 5, 6)

scala> val goat = List("Ronaldo", "Johan Cruyff", "Diego M", "Pele") scala> goat.sorted res0: List[String] = List(Diego M, Johan Cruyff, Pele, Ronaldo)

以上例子表明scala默认以升序排序。哪如何进行降序排列方法有哪些?

  1. 使用集合类库的reverse函数

scala> res0.reverse res1: List[String] = List(Ronaldo, Pele, Johan Cruyff, Diego M)

  1. 使用sorted的排序方法

排序作为通用的方法,scala会提供完善的API的。那么如何使用sorted进行排序哪?猫腻在隐式参数转换Ordering参数上。查询Ordering api中包含reverse可以满足降序排列。

/** Return the opposite ordering of this one. */
override def reverse: Ordering[T] = new Ordering[T] {
  override def reverse = outer
  def compare(x: T, y: T) = outer.compare(y, x) //compare方法 x,y有(x,y)变成(y,x)
}

发现踪迹后,实现降序排列只需要显示调用Ordering参数即可。

scala> goat.sorted(Ordering[String].reverse) //效果和 goat.sorted.reverse一致 res5: List[String] = List(Ronaldo, Pele, Johan Cruyff, Diego M)

整型数组按降序进行排序:

scala> List(1,6,4,5).sorted(Ordering[Int].reverse) res4: List[Int] = List(6, 5, 4, 1) //降序,隐式转换很奇妙呀

  • sortBy排序

上面的示例是对一种对象类型进行排序,即对整型、字符串的数组进行。在应用时,我们遇到一个对象多属性进行排序,如信息包含个人名称和年龄,从这2个维度进行排序要怎样进行哪?

val idol = List(("Ronaldo",41), ("Johan Cruyff",72), ("Diego M",56), ("Riva",41))

这种类型数据, sortBy可解决该问题。

scala> idol .sortBy{case (name,age) => (age, name)} res6: List[(String, Int)] = List((Riva,41), (Ronaldo,41), (Diego M,56), (Johan Cruyff,72))

scala> goat.sortBy{case (name,age) => (name, age)} res7: List[(String, Int)] = List((Diego M,56), (Johan Cruyff,72), (Riva,41), (Ronaldo,41))

按照 age-name排序,注意2种排序方式差异,age相同比较name,Riva\Ronaldo 显示排序的差别。

name按照降序排序,age按照升序排序,示例:

scala> goat.sortBy{case (name,age) => (name, age)}(Ordering.Tuple2(Ordering.String.reverse,Ordering.Int)) res9: List[(String, Int)] = List((Ronaldo,41), (Riva,41), (Johan Cruyff,72), (Diego M,56))

Ordering是伴生对象,sorted中引用的类型是trait。

sortBy函数签署参数是 f:A=>B表示能够对不同类型的参数进行转换。那么,不同业务排序方式不同,这种情况下,如何进行按照业务进行排序哪?

  • 自定义排序方式

自定义排序是自己编写排序的方法。

class Person(id:String,age:Int,address:String) 
val t:List[Person] = ??? // 对Person的列表进行排序
//编写person的比较规则,使用隐式转换自动的进行转换
//编写Person的排序规则也很简单
object tx {
 trait PersonOrdering extends Ordering[Person] { //比较规则
   def compare(x: Person, y: Person): Int =
    // 排序规则实现, 地址改成小写,然后进行字符串比较
    if(x.address.toLowerCase > y.address.toLowerCase) 1 else -1
 }
 implicit object PersonOrdered extends PersonOrdering //隐式转换
}
//如何使用
import tx._
t.sorted(Ordering[Person]) 

代码实现的方式是导入object 完成隐式转换,也可以尝试使用 隐式类、隐式函数或变量的方式。

  • sortWith 排序

    sortWith也是自定义排序的一种方式,通过改变参数的类型完成比较。因为原理上使用sorted方法,使用方法和sorted类似,使用方法不赘述。

总结

本篇介绍scala里面的三种排序函数,以及如何进行升降序排列。每种都有其各自的应用场景:

sorted:适合单集合的升降序

sortBy:适合对单个或多个属性的排序,代码量比较少,推荐使用这种

sortWith:适合定制化场景比较高的排序规则,用法和sorted类似。

另外,粗略介绍了隐式转换在排序中使用。

陌上人如玉,公子世无双. 希望给你带来灵感.

相关文章

  • scala 排序函数使用和代码分析

    引用 转载 请注明出处 scala & java 关系不清,爱者,为止疯狂。怨者,无力吐槽。但在一个方面是无可争议...

  • Scala笔记

    Scala基础 学习twitter的scala教程的笔记 函数 函数定义,scala语法中可以使用多种方式定义函数...

  • scala的函数使用分析

    scala的函数定义及使用知识点挺多,有类型型变(不变、型变、逆变)知识,有 call-by-name和call-...

  • 选择排序(oc/java/Python/scala)

    一、浅谈数组和链表 二、 选择排序介绍: 方案一: scala实现代码: Java实现代码: OC实现代码: 主文...

  • scala 匿名函数

    定义 Scala 中定义匿名函数的语法很简单,箭头左边是参数列表,右边是函数体。使用匿名函数后,我们的代码变得更简...

  • Scala模式匹配及偏函数

    模式匹配公式: 一、代码Demo 二、Scala中的模式匹配处理异常 三、Scala函数

  • Spark中的的sortBy排序(方法与算子的不同)

    Scala中有排序函数 (1)sorted 对一个集合进行自然排序,通过传递隐式的Ordering (2)sort...

  • 排序算法1: 冒泡排序算法

    C++ 冒泡排序算法的实例源代码,一些排序方法的代码集锦,该函数模板使用冒泡法对集合元素进行排序,参数说明: co...

  • Scala编程的基础知识

    Scala是一个面向对象的函数式编程语言,在Scala中,一切皆函数。 函数式编程的优点: 提高生产效率,代码量更...

  • 关于执行Analyze静态分析一些相关问题

    说明 使用Xcode自带的静态分析工具可以找出代码潜在错误,如内存泄露,未使用函数和变量等缺点:静态内存分析由于是...

网友评论

    本文标题:scala 排序函数使用和代码分析

    本文链接:https://www.haomeiwen.com/subject/fixopqtx.html