【问题标题】:Scala sorting of case classes by typeScala按类型对案例类进行排序
【发布时间】:2020-10-17 00:04:39
【问题描述】:

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

  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
    }
  }

然而,这显然会扩展得非常可怕,而且看起来不太好看..

【问题讨论】:

    标签: scala sorting functional-programming pattern-matching case-class


    【解决方案1】:

    只需像这样为Element 定义一个implicit Ordering

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

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

    【讨论】:

    • 哦,我不知道Ordering.by 是一个东西。这当然会让事情变得容易得多。
    【解决方案2】:

    如何引入一个类,该类将拥有对元素进行排序的优先级,例如:

    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()
    

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

    由于您只想将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)
    

    【讨论】:

    • 这是个好主意!它甚至似乎是一个很明显的选择,只需提供一个可以隐式用于排序的字段。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多