Scala:A延伸订购[A]

时间:2015-02-05 16:20:35

标签: scala sorting generics

我刚刚开始学习Scala,我决定在练习时创建一个Pair [A,B]类,它在排序后首先按As排序,然后按Bs排序。我的第一次尝试是这样的:

case class Pair[A <: Ordered[A], B <: Ordered[B]](val left: A, val right: B) extends Ordered[Pair[A, B]]
{
  override def compare(that: Pair[A, B]) = {
      val leftCompare = this.left.compare(that.left)
      if (leftCompare == 0)
        this.right.compare(that.right)
      else
        leftCompare
    }
}

object Main extends App
{
  List(Pair(1, "a"), Pair(5, "b"), Pair(5, "a"), Pair(1, "b")).sorted
}

这就是我希望它完成的方式。我想扩展Ordered并让它工作,所以我可以做像List(无论).sortWith(_&lt; _)或List(无论如何).sorted,就像我在Main中写的那样。我收到以下错误:

pair.scala:14: error: inferred type arguments [Int,String] do not conform to method apply's type parameter bounds [A <: Ordered[A],B <: Ordered[B]]
  List(Pair(1, "a"), Pair(5, "b"), Pair(5, "a"), Pair(1, "b")).sorted

这对于列表中的每一对都是:

pair.scala:14: error: type mismatch;
 found   : Int(1)
 required: A
  List(Pair(1, "a"), Pair(5, "b"), Pair(5, "a"), Pair(1, "b")).sorted

这也是我不了解的:

pair.scala:14: error: diverging implicit expansion for type scala.math.Ordering[Pair[_ >: A with A with A with A <: scala.math.Ordered[_ >: A with A with A with A <: scala.math.Ordered[_ >: A with A with A with A]], _ >: B with B with B with B <: scala.math.Ordered[_ >: B with B with B with B <: scala.math.Ordered[_ >: B with B with B with B]]]]
starting with method $conforms in object Predef
  List(Pair(1, "a"), Pair(5, "b"), Pair(5, "a"), Pair(1, "b")).sorted

我设法让它进行排序,但只能通过编写知道他们正在排序的类型的排序函数,而不是仅仅意识到他们正在排序可排序的类型。以下是这些“了解类型”版本的内容,正如我已经提到的那样:

case class Pair[A, B](val left: A, val right: B)
{}

object Main extends App
{
  val pairs = Array(Pair(1, "a"), Pair(5, "b"), Pair(5, "a"), Pair(1, "b"))
  Sorting.quickSort(pairs)(Ordering[(Int, String)].on(x => (x.left, x.right)))
  println(pairs.toList)
}

case class Pair[A, B](val left: A, val right: B)
{}

object Main extends App
{
  val intStringSort = (x: Pair[Int, String], y: Pair[Int, String]) => {
    val intCompare = x.left - y.left
    if (intCompare == 0)
      x.right.compare(y.right) < 0
    else
      intCompare < 0
  }
  println(List(Pair(1, "a"), Pair(5, "b"), Pair(5, "a"), Pair(1, "b")).sortWith(intStringSort))
}

提前致谢。

2 个答案:

答案 0 :(得分:4)

使用<%代替<:

case class Pair[A <% Ordered[A], B <% Ordered[B]]

因为IntString都不是Ordered

<强>更新

但是IntRichInt的隐式转换是Ordered[Int],而StringStringOps的转换是Ordered[String]

<%表示可以将对象隐式转换为已定义的类型。 例如,A <% Ordered[A]的{​​{1}}表示存在从IntInt的隐式转换,即:

Ordered[Int]
implicit def intWrapper(x: Int) = new runtime.RichInt(x) 中自动导入的

scala.PredefRichInt。对Ordered[Int]执行了类似的步骤。

答案 1 :(得分:2)

问题在于您的类型范围,A <: Ordered[A]B <: Ordered[B]

IntString不会延长Ordered。但是它们在范围内确实有隐式Ordering,因此您可以使用隐式边界而不是类型边界。

case class Pair[A, B](left: A, right: B)(implicit a: Ordering[A], b: Ordering[B]) extends Ordered[Pair[A, B]] {

    def compare(that: Pair[A, B]) = {
        val leftCompare = a.compare(this.left, that.left)
        if (leftCompare == 0)
            b.compare(this.right, that.right)
        else
            leftCompare
    }

}

scala> List(Pair(1, "a"), Pair(3, "d"), Pair(2, "c"), Pair(2, "b")).sorted
res8: List[Pair[Int,String]] = List(Pair(1,a), Pair(2,b), Pair(2,c), Pair(3,d))

请注意,我在案例类定义中删除了val,因为案例类字段是自动公开的。 compare也不需要override,因为它需要实现(尽管它可能是某些人的样式偏好)。