Use an immutable hash map for the concrete value, omitting zero-count entries:
class CompleteMultiSetImp[T](initial: Map[T, Int]) extends CompleteMultiSet[T] {
  private val table = initial.filter { case (_, n) => n != 0 }
  override def count(t: T): Int = table.getOrElse(t, 0)
  override lazy val present: Seq[T] = table.keys.toVector
}

def cms[T](ts: T*): CompleteMultiSet[T] =
  new CompleteMultiSetImp[T](ts.distinct.map(t => (t, 1)).toMap)
The abstraction function is the map with implicit zero outside its keys. Immutable storage makes saved values independent of later operations, and the inherited defaults dispatch through the overridden count and present. A hash lookup has expected constant cost under ordinary hashing assumptions, with collision-dependent worst cases.
Repeated arguments still get count one, because the constructor first removes duplicates. All other elements have count zero, satisfying the intended stronger reading of the constructor specification. Treating ts as a bag and adding one for every repetition would implement a different operation.

Articles by others on the same topic (0)

There are currently no matching articles.