Scala 按类型对案例 类 进行排序

Scala sorting of case classes by type

鉴于某些情况 类 扩展了一个共同特征,我希望能够根据它们的类型定义一个排序(实际上不一定,目标是以这种方式对它们进行排序)。例如:

  sealed trait Element
  case class A(x: Int) extends Element
  case class B(x: Int) extends Element
  case class C(x: Int) extends Element
  case class D(x: Int) extends Element
  case class E(x: Int) extends Element
  case class F(x: Int) extends Element

  val elements: List[Element] = List(
    A(5), F(3), E(1), C(19), A(3), F(1)
  )

排序为 F -> A -> all other cases,结果列表为 List(F(3), F(1), A(5), A(3), E(1), C(19))。相同类型的元素之间的顺序无关紧要。

我想出了多种不同的解决方案,但它们看起来都很复杂,我只是觉得我缺少一些明显的方法来实现这一点。这就是我使用排序实现它的方式:

  val sorted = elements.sorted{(a: Element, b: Element) => (a, b) match {
      case (_: F, _: F) =>  0
      case (_: F, _   ) => -1
      case (_   , _: F) =>  1
      case (_: A, _: A) =>  0
      case (_: A, _   ) => -1
      case (_   , _: A) =>  1
      case _            =>  0
    }
  }

然而,这显然会非常可怕,而且看起来也不好..

引入一个class怎么样,它会优先排序元素,例如:

class Prio(val prio: Int) {}
case class A() extends Prio(5)
case class B() extends Prio(3)
case class C() extends Prio(9)
case class D() extends Prio(7)

object Prio {
  def main(args: Array[String]): Unit = {
    List(A(), B(), C(), D())
      .sortBy(_.prio)
      .foreach(println)
  }
}

结果如下:

B()
A()
D()
C()

你当然可以混入其他接口,为类型class添加值。 Prio class 甚至可以丰富更多的优先级,可以在不同的情况下使用。

因为您只想让 A 在前,F 在后,您可以使用以下顺序:

class Prio(val prio: Int) {}
case class A() extends Prio(-1)
case class B() extends Prio(0)
case class C() extends Prio(0)
case class D() extends Prio(0)
case class E() extends Prio(0)
case class F() extends Prio(1)

只需为 Element 定义一个 implicit Ordering,如下所示:

object Element {
  implicit val ord: Ordering[Element] = Ordering.by {
    case _: F => 0
    case _: A => 1
    case _ => 2
  }
}

那么elements.sorted会给你想要的答案