scala如何命令元组?

时间:2014-10-08 09:57:52

标签: scala

我试图了解scala如何处理元组的排序和排序

例如,如果我得到了列表

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

scala知道如何对其进行排序:

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

但是元组没有&#39;&lt;&#39;方法:

l.sortWith(_ < _)

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

scala如何知道如何对这些元组进行排序?

2 个答案:

答案 0 :(得分:19)

因为sorted具有隐式参数ord

  

def sort [B&gt;:A](隐式ord:math.Ordering [B]):List [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)] = scala.math.Ordering$$anon$11@11bbdc80

当然,您可以定义自己的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]支持以下所有方法:<<=>,{{1 }}

>=

答案 1 :(得分:4)

@ Eastsun的回答很好地解释了你的问题的第一部分“Scala如何排序元组”。

关于第二部分“为什么没有元组有<方法”:在Scala中,像<这样的比较器转换为基本类型的本机JVM比较(比较Int时或Double等)或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