Scala 2.13: Efficiently extracting an element from a SortedSet

Assume I have:

case class JobID(i: Int):
  @targetName("minus") 
  def -(other: JobID): Int = i - other.i
end JobID

case class Job( id:          JobID, 
                start:       Instant          = ZeroInstant, 
                total:       Duration         = ZeroDuration
              )

object JobIDOrdering extends Ordering[Job]:
  override def compare(a: Job, b: Job): Int = 
    val byID = a.id - b.id
    byID

val completed: SortedSet[Job] = SortedSet()(JobIDOrdering)

At some point in my code I hold 2 references to Job with the same JobID. One (job) is external and the other an updated version of job:Job stored in the completed set. So my question is: how can I efficiency extract the updated instance inside the set using the “external” job?

I came up with the following solution:

val updatedJob = completed.intersect(SortedSet(job)(JobIDOrdering)).head

but that seems too complex for such a simple goal. I find no “get” method. Am I missing something?

TIA

Why not using a SortedMap[JobID, Job] instead?

@BalmungSan good solution. Solves the “issue”. Still, I find it strange that I cannot “extract” an element from the set by its sorting condition.

Thank you.

I think this is a FAQ. Normally, a set lets you query membership with contains. To extract other data (than the key data), use a map.

scala> case class K(n: Int)
class K

scala> case class J(k: K, s: String)
class J

scala> val js = collection.SortedSet(J(K(42),"x"),J(K(17),"y"))(Ordering.by((j: J) => j.k.n))
val js: scala.collection.SortedSet[J] = TreeSet(J(K(17),y), J(K(42),x))

scala> val item = J(K(42), "z")
val item: J = J(K(42),z)

scala> js.rangeFrom(item)
val res0: scala.collection.SortedSet[J] = TreeSet(J(K(42),x))

scala> js.rangeFrom(item).firstKey
val res1: J = J(K(42),x)

Oh wait, there’s

scala> js.minAfter(J(K(40),""))
val res2: Option[J] = Some(J(K(42),x))

scala> js.minAfter(J(K(42),"")).filter(_.k.n == 42)
val res3: Option[J] = Some(J(K(42),x))

scala> js.minAfter(J(K(40),"")).filter(_.k.n == 40)
val res4: Option[J] = None

Java has ceiling (that returns null for absence), and tailSet.

I don’t know which nomenclature would help me remember the API.

2 Likes

@som-snytt rangeFrom seems to do the job. Thank you.