2014-10-08 91 views
12

我想了解斯卡拉如何處理順序和元組scala如何訂購元組?

例如分選,如果我得到的名單

val l = for {i <- 1 to 5} yield (-i,i*2) 
Vector((-1,2), (-2,4), (-3,6), (-4,8), (-5,10)) 

斯卡拉知道如何對它進行排序:

l.sorted 
Vector((-5,10), (-4,8), (-3,6), (-2,4), (-1,2)) 

但元組沒有'<'方法:

l.sortWith(_ < _) 

error: value < is not a member of (Int, Int) 
l.sortWith(_ < _) 

scala如何知道如何對這些元組進行排序?

回答

16

因爲sorted有一個隱含的參數ord

DEF排序[B>:A](隱式ORD:math.Ordering [B]):列表[A]排序 根據訂購該序列。

該排序穩定。也就是說,相同的元素(由 lt確定)在排序序列中以與原始 相同的順序出現。

ord要用於比較元素的順序。

並且在scala.math.Ordering定義的隱式轉換:

implicit def Tuple2[T1, T2](implicit ord1: Ordering[T1], 
            ord2: Ordering[T2]): Ordering[(T1, T2)] 

所以l.sorted將被轉換到l.sorted(scala.math.Ordering.Tuple2[Int, Int]())

測試:

scala> def catchOrd[A](xs: A)(implicit ord: math.Ordering[A]) = ord 
catchOrd: [A](xs: A)(implicit ord: scala.math.Ordering[A])scala.math.Ordering[A] 

scala> catchOrd((1,2)) 
res1: scala.math.Ordering[(Int, Int)] = [email protected] 

當然,你可以定義你自己的Ordering

scala> implicit object IntTupleOrd extends math.Ordering[(Int, Int)] { 
    | def compare(x: (Int, Int), y: (Int, Int)): Int = { 
    |  println(s"Hi, I am here with x: $x, y: $y") 
    |  val a = x._1*x._2 
    |  val b = y._1*y._2 
    |  if(a > b) 1 else if(a < b) -1 else 0 
    | } 
    | } 
defined object IntTupleOrd 

scala> Seq((1, 10), (3, 4), (2, 3)).sorted 
Hi, I am here with x: (1,10), y: (3,4) 
Hi, I am here with x: (3,4), y: (2,3) 
Hi, I am here with x: (1,10), y: (2,3) 
res2: Seq[(Int, Int)] = List((2,3), (1,10), (3,4)) 

編輯有使Tuple[Int, Int]支持以下所有方法的簡便方法:<<=>>=

scala> implicit def mkOps[A](x: A)(implicit ord: math.Ordering[A]): ord.Ops = 
    | ord.mkOrderingOps(x) 
mkOps: [A](x: A)(implicit ord: scala.math.Ordering[A])ord.Ops 

scala> (1, 2) < (3, 4) 
res0: Boolean = true 

scala> (1, 2) <= (3, 4) 
res1: Boolean = true 

scala> (1, 2, 3) <= (1, 2, 4) 
res2: Boolean = true 

scala> (3, 3, 3, 3) >= (3, 3, 3, 4) 
res3: Boolean = false 
+0

我不知道。排序元組有時會導致混淆結果。 (100L,2D)::(2L,5001D)::無分類的' 給出: '列表((2,5001.0),(100,2.0))'。看起來這個元組的第二個元素沒有權重。 – Ashesh 2016-11-09 16:55:48

+3

僅當第一個元素相等時,排序纔會查看元組的第二個元素。 – Ashesh 2016-11-09 17:15:05

4

@ Eastsun的答案很好地解釋了你的問題的第一部分「Scala如何排序元組」。

關於第二部分「爲什麼不元組具有<方法」:在Scala中,比較器等<或者(比較IntDouble等時)就轉化爲基本類型的原生JVM比較或至someClass成員函數與類型<(that: someClass): Boolean。這種情況實際上只是語法糖:someObject < otherObject轉換爲someObject.<(otherObject)。如果你想擁有此功能的元組,你可以把一個隱含的類爲範圍,並映射比較成員函數由Ordering提供的比較:

implicit class ProvideComparator[T](t1: T)(implicit ord: Ordering[T]) { 
    def <(t2: T) = ord.lt(t1, t2) 
    def >(t2: T) = ord.gt(t1, t2) // and so on 
} 

現在你可以這樣寫:

scala> (1,2) < (2,2) 
res2: Boolean = true