如何对密封性状进行排序?



我有一个由某种"状态机"("流程图"(定义的分布式系统

每个系统在共享的"日志"中写入状态

我将每个状态表示为密封特征的一部分和该状态的给定"状态">

我想"合并/减少"为代表当前进度的单个状态。

(有一些放松,因为并非所有人都必须成功才能成功完成最终状态(

有 2 个密封特征表示流:

sealed trait System
case object A extends System
case object B extends System
case object C extends System
...
sealed trait Status
case object Pending extends Status
case object InProgress extends Status
case object Success extends Status
case object Fail extends Status

日志:

A, Success
B, Fail
C, Pending
...
...

现在有一组规则,我用它来定义单个状态降低

基本上它优先考虑

A < B < C, ... < Z

Pending < InProgress < Success < Fail

因此,如果状态为:

(A, Success)(C, Pending)

我想将其减少到(C,Pending)

如果

(A,Success)(B, Fail)

我想将其减少到(B, Fail)

在我的情况下,我可以将其建模为简单的整数比较(可能带有我显式测试的异常值(

我不清楚如何使密封特征具有可比性/可排序性,这将使我的生活更轻松

沿着这些思路的东西就足够了:

def reduce(states: Seq[(System,Status)]) : (System,Status) = {
states.order... {left.system < right.system) && (a.status < b.status) ... possibly another ordering test ....}.tail // take the last one in the ordering
}

您可以定义一个scala.math.Ordering[Status]

object StatusOrdering extends Ordering[Status] {
def compare(x: Status, y: Status): Int =
(x, y) match {
// assuming that the ordering is Pending < InProgress < Success < Fail...
case (_, _) if (x eq y) => 0
case (Pending, _) => -1
case (_, Pending) => 1
case (InProgress, _) => -1
case (_, InProgress) => 1
case (Success, _) => -1
case (_, Success) => 1
case _ => 0 // (Fail, Fail)
}

在您的reduce中,您可以

import StatusOrdering.mkOrderingOps

您的Status对象将丰富<和朋友。

也可以让你的trait扩展Ordered[Status],它定义了特征中的规范排序:

sealed trait OrderedStatus extends Ordered[OrderedStatus] {
def compare(that: OrderedStatus): Int =
(this, that) match {
case (x, y) if (x eq y) => 0
case (Qux, _) => -1
case (_, Qux) => 1
case (Quux, _) => -1
case (_, Quux) => 1
case _ => 0
}
}
case object Qux extends OrderedStatus
case object Quux extends OrderedStatus
case object Quuux extends OrderedStatus

那么你不必导入mkOrderingOps,但我个人不喜欢在compare方法中向前使用扩展case objects(并且在每种情况下对象的样板compare的替代方案甚至更糟(。

一种方法是在几个Map内定义SystemStatus的优先级,然后通过Ordering.by定义(System, Status)的顺序:

val syMap: Map[System, Int] = Map(A->1, B->2, C->3)
val stMap: Map[Status, Int] = Map(Pending->1, InProgress->2, Success->3, Fail->4)
implicit val ssOrdering: Ordering[(System, Status)] =
Ordering.by{ case (sy, st) => (syMap.getOrElse(sy, 0), stMap.getOrElse(st, 0)) }
import ssOrdering._
(A, Success) < (C, Pending)
// res1: Boolean = true
(A, Success) < (B, Fail)
// res2: Boolean = true
(C, Pending) < (B, Fail)
// res3: Boolean = false

请注意,在上面的示例代码中,不匹配System/Status的默认值设置为0(对于最低优先级(。 可以根据需要将其设置为任何其他值。

要减少(System, Status)秒的Seq

def ssReduce(ss: Seq[(System, Status)])(implicit ssOrd: Ordering[(System, Status)]) : (System, Status) = {
import ssOrd._
ss.reduce((acc, t) => if (t < acc) acc else t )  // Or simply `ss.max`
}
ssReduce(Seq((A, Success), (C, Pending), (B, Fail)))
// res4: (System, Status) = (C,Pending)

考虑枚举猫CatsOrderValueEnum定义顺序的方法

import cats.Order
import enumeratum.values._
import cats.instances.int._
sealed abstract class Status(val value: Int) extends IntEnumEntry
object Status extends CatsOrderValueEnum[Int, Status] with IntEnum[Status] {
case object Pending    extends Status(1)
case object InProgress extends Status(2)
case object Success  extends Status(3)
case object Fail  extends Status(4)
val values = findValues
}
object AdtOrder extends App {
import Status._
println(Order[Status].compare(Pending, Fail))
}

哪些输出

-1

哪里

libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % "1.5.13",
"com.beachape" %% "enumeratum-cats" % "1.5.15"
)

一旦你为每个case object分配一个整数,你就可以编写自己的Ordering#compare方法,只需减去它们:

sealed trait System
case object A extends System
case object B extends System
case object C extends System
case object D extends System
object System {
implicit val ordering: Ordering[System] = new Ordering[System] {
def compare(x: System, y: System): Int = {
def id(value: System): Int = value match {
case A => 0
case B => 1
case C => 2
case D => 3
}
id(x) - id(y)
}
}
}
sealed trait Status
case object Pending extends Status
case object InProgress extends Status
case object Success extends Status
case object Fail extends Status
object Status {
implicit val ordering: Ordering[Status] = new Ordering[Status] {
def compare(x: Status, y: Status): Int = {
def id(value: Status): Int = value match {
case Pending => 0
case InProgress => 1
case Success => 2
case Fail => 3
}
id(x) - id(y)
}
}
}

然后,您可以轻松对序列进行排序:

val sorted = Seq((D, Fail), (D,Pending), (A,Fail), (D,InProgress)).sorted
// val sorted = List((A, Fail), (D, Pending), (D, InProgress), (D, Fail))

相关内容

  • 没有找到相关文章

最新更新