第十章 Scala 容器基礎(二十八):集合排序

Problem

    你想要對一個集合元素進行排序。或者你想定義一個自定義類來實現Ordered trait,來讓你可使用sorted方法,或者使用比較操符<,<=,>,>=來對類的實例進行比較。算法

Solution

    你可使用sorted或者sortWith方法來對集合進行排序。app

    Sorted方法能夠對集合元素類型爲Double,Float,Int和其餘能夠隱試轉化scala.math.Ordering的進行排序。ide

scala> val l = List(10, 5, 8, 1, 7).sorted
l: List[Int] = List(1, 5, 7, 8, 10)

scala> val b = List("banana", "pear", "apple", "orange").sorted
b: List[String] = List(apple, banana, orange, pear)

    Rich版本的numeric類(好比RichInt)和StringOps類都實現了Ordered trait,因此他們可使用sorted方法實現排序。this

    SortWith方法讓你可使用本身的排序邏輯來實現排序規則。下面的例子展現瞭如何對集合元素類型爲Int和String使用sortWith排序:spa

scala> List(10, 5, 8, 1, 7).sortWith(_ < _)
res14: List[Int] = List(1, 5, 7, 8, 10)

scala> List(10, 5, 8, 1, 7).sortWith(_ > _)
res15: List[Int] = List(10, 8, 7, 5, 1)

scala> List("banana", "pear", "apple", "orange").sortWith(_ < _)
res16: List[String] = List(apple, banana, orange, pear)

scala>  List("banana", "pear", "apple", "orange").sortWith(_ > _)
res17: List[String] = List(pear, orange, banana, apple)

    你的排序方法的複雜度取決於你的排序需求。舉個例子,你能夠經過sort訪問元素的方法,好比下面這個例子,按長度對一個字符串集合進行排序:scala

scala> List("banana", "pear", "apple", "orange").sortWith(_.length < _.length)
res18: List[String] = List(pear, apple, banana, orange)

scala> List("banana", "pear", "apple", "orange").sortWith(_.length > _.length)
res19: List[String] = List(banana, orange, apple, pear)

    若是你的排序方法很是複雜或者會被重複使用,那麼你能夠先定義這個方法後,再調用此方法:excel

scala> def sortByLength(s1: String, s2: String) = {
     |   println("compare %s and %s".format(s1, s2))
     |   s1.length > s2.length
     | }
sortByLength: (s1: String, s2: String)Boolean

scala> List("banana", "pear", "apple").sortWith(sortByLength)
compare pear and banana
compare banana and pear
compare apple and pear
compare apple and pear
compare apple and banana
compare banana and apple
res20: List[String] = List(banana, apple, pear)

Discussion

    若是你定義的類,沒有定義對Ordering的隱式轉換,那麼你就沒有辦法經過調用sorted方法來對集合元素進行排序。code

scala> class Person(var name: String) {
     |   override def toString = name
     | }
defined class Person

    建立一個Person集合:orm

scala> val ty = new Person("Tyler")
ty: Person = Tyler

scala> val al = new Person("Al")
al: Person = Al

scala> val paul = new Person("Paul")
paul: Person = Paul

scala> val dudes = List(ty, al, paul)
dudes: List[Person] = List(Tyler, Al, Paul)

    若是你調用sorted方法對dudes進行排序,那麼你會看到下面的錯誤提示:對象

scala> dudes.sorted
<console>:13: error: No implicit Ordering defined for Person.
              dudes.sorted
                    ^

    可是你可使用sortWith對dudes進行排序:

scala> dudes.sortWith(_.name < _.name)
res1: List[Person] = List(Al, Paul, Tyler)

scala> dudes.sortWith(_.name > _.name)
res2: List[Person] = List(Tyler, Paul, Al)
Mix in the Ordered trait

    混入Ordered特質可以讓你的程序使用sorted方法來對Person集合進行排序,可是你必須實現compare方法。

class Person(var name: String) extends Ordered[Person]{
  override def toString = name

  override def compare(that: Person): Int = {
    if (this.name == that.name) return 0
    else if (this.name > that.name) return 1
    else return -1
  }
}

    這個新的Person類就可使用sorted方法來進行排序了。

    Compare方法提供了排序功能,compare方法會這樣進行工做:

  • 若是兩個對象相等,返回0

  • 若是this<that那麼返回一個負數

  • 若是shit>that那麼返回一個正數

    類的兩個實例誰大誰小徹底取決於你的compare算法,由於目前這個算法僅僅比較兩個字符串的值,因此也能夠寫成這樣:

def compare (that: Person) = this.name.compare(that.name)

    使用Ordered特質的另一個好處是它可讓你在代碼中直接比較對象實例。

if (al > ty) println("Al") else println("Tyler")

    上面代碼之因此能夠工做是由於Ordered特質實現了<=, <, >, >=方法,並調用你定義的compare方法來使之生效。

See Also

For more information, the Ordered and Ordering Scaladoc is excellent, with good examples of this approach, and other approaches.

• The Ordering trait

• The Ordered trait

相關文章
相關標籤/搜索