diff --git a/README.md b/README.md index 19a9d95..b13dbe3 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ Here is the [full Scaladoc](https://static.javadoc.io/org.scala-lang.modules/sca These collections are in the `scala.collection` package. -- [`MultiSet`](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/MultiSet.html) (both [mutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/mutable/MultiSet.html) and [immutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/immutable/MultiSet.html)) -- [`SortedMultiSet`](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/SortedMultiSet.html) (both [mutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/mutable/SortedMultiSet.html) and [immutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/immutable/SortedMultiSet.html)) +- [`Bag`](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/Bag.html) (both [mutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/mutable/Bag.html) and [immutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/immutable/Bag.html)) +- [`SortedBag`](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/SortedBag.html) (both [mutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/mutable/SortedBag.html) and [immutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/immutable/SortedBag.html)) - [`MultiDict`](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/MultiDict.html) (both [mutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/mutable/MultiDict.html) and [immutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/immutable/MultiDict.html)) - [`SortedMultiDict`](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/SortedMultiDict.html) (both [mutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/mutable/SortedMultiDict.html) and [immutable](https://static.javadoc.io/org.scala-lang.modules/scala-collection-contrib_2.13/0.2.0/scala/collection/immutable/SortedMultiDict.html)) diff --git a/src/main/scala/scala/collection/MultiSet.scala b/src/main/scala/scala/collection/Bag.scala similarity index 84% rename from src/main/scala/scala/collection/MultiSet.scala rename to src/main/scala/scala/collection/Bag.scala index ba42d58..d6da711 100644 --- a/src/main/scala/scala/collection/MultiSet.scala +++ b/src/main/scala/scala/collection/Bag.scala @@ -3,26 +3,28 @@ package scala.collection import scala.util.hashing.MurmurHash3 /** - * A multiset is a set that can contain multiple occurrences of a same value. + * A bag is an unordered collection that can contain multiple occurrences of the same value. + * + * Two bags are defined to be equal if they have the same elements, and the same number of occurrences of each element. * * @tparam A the element type of the collection */ -trait MultiSet[A] +trait Bag[A] extends Iterable[A] - with MultiSetOps[A, MultiSet, MultiSet[A]] + with BagOps[A, Bag, Bag[A]] with Equals { - override protected[this] def className: String = "MultiSet" + override protected[this] def className: String = "Bag" - override def iterableFactory: IterableFactory[MultiSet] = MultiSet - override protected def fromSpecific(coll: IterableOnce[A]): MultiSet[A] = iterableFactory.from(coll) - override protected def newSpecificBuilder: mutable.Builder[A, MultiSet[A]] = iterableFactory.newBuilder - override def empty: MultiSet[A] = iterableFactory.empty + override def iterableFactory: IterableFactory[Bag] = Bag + override protected def fromSpecific(coll: IterableOnce[A]): Bag[A] = iterableFactory.from(coll) + override protected def newSpecificBuilder: mutable.Builder[A, Bag[A]] = iterableFactory.newBuilder + override def empty: Bag[A] = iterableFactory.empty def canEqual(that: Any): Boolean = true override def equals(o: Any): Boolean = o match { - case that: MultiSet[A] => + case that: Bag[A] => (this eq that) || (that canEqual this) && (this.size == that.size) && { @@ -39,7 +41,7 @@ trait MultiSet[A] } -trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] +trait BagOps[A, +CC[X] <: Bag[X], +C <: Bag[A]] extends IterableOps[A, CC, C] { protected[this] def fromSpecificOccurrences(it: Iterable[(A, Int)]): C = @@ -126,4 +128,4 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] } -object MultiSet extends IterableFactory.Delegate(immutable.MultiSet) \ No newline at end of file +object Bag extends IterableFactory.Delegate(immutable.Bag) \ No newline at end of file diff --git a/src/main/scala/scala/collection/SortedMultiSet.scala b/src/main/scala/scala/collection/SortedBag.scala similarity index 74% rename from src/main/scala/scala/collection/SortedMultiSet.scala rename to src/main/scala/scala/collection/SortedBag.scala index 0e532f7..a7804c3 100644 --- a/src/main/scala/scala/collection/SortedMultiSet.scala +++ b/src/main/scala/scala/collection/SortedBag.scala @@ -3,25 +3,25 @@ package scala.collection import scala.annotation.unchecked.uncheckedVariance /** - * Multiset whose elements are sorted + * Bag whose elements are sorted * @tparam A Type of elements */ -trait SortedMultiSet[A] - extends MultiSet[A] - with SortedMultiSetOps[A, SortedMultiSet, SortedMultiSet[A]] { +trait SortedBag[A] + extends Bag[A] + with SortedBagOps[A, SortedBag, SortedBag[A]] { - def unsorted: MultiSet[A] = this + def unsorted: Bag[A] = this - def sortedIterableFactory: SortedIterableFactory[SortedMultiSet] = SortedMultiSet - override protected def fromSpecific(coll: IterableOnce[A]): SortedMultiSet[A] = sortedIterableFactory.from(coll)(ordering) - override protected def newSpecificBuilder: mutable.Builder[A, SortedMultiSet[A]] = sortedIterableFactory.newBuilder(ordering) - override def empty: SortedMultiSet[A] = sortedIterableFactory.empty(ordering) - override def withFilter(p: A => Boolean): SortedMultiSetOps.WithFilter[A, MultiSet, SortedMultiSet] = new SortedMultiSetOps.WithFilter(this, p) + def sortedIterableFactory: SortedIterableFactory[SortedBag] = SortedBag + override protected def fromSpecific(coll: IterableOnce[A]): SortedBag[A] = sortedIterableFactory.from(coll)(ordering) + override protected def newSpecificBuilder: mutable.Builder[A, SortedBag[A]] = sortedIterableFactory.newBuilder(ordering) + override def empty: SortedBag[A] = sortedIterableFactory.empty(ordering) + override def withFilter(p: A => Boolean): SortedBagOps.WithFilter[A, Bag, SortedBag] = new SortedBagOps.WithFilter(this, p) } -trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] - extends MultiSetOps[A, MultiSet, C] +trait SortedBagOps[A, +CC[X] <: Bag[X], +C <: Bag[A]] + extends BagOps[A, Bag, C] with SortedOps[A, C] { def sortedIterableFactory: SortedIterableFactory[CC] @@ -30,8 +30,8 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] protected def sortedFromOccurrences[B : Ordering](it: Iterable[(B, Int)]): CC[B] = sortedFromIterable(it.view.flatMap { case (b, n) => new View.Fill(n)(b) }) - /** `this` sorted multiset upcasted to an unsorted multiset */ - def unsorted: MultiSet[A] + /** `this` sorted bag upcasted to an unsorted bag */ + def unsorted: Bag[A] def occurrences: SortedMap[A, Int] @@ -60,61 +60,61 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] rangeUntil(next) } - /** Builds a new sorted multiset by applying a function to all elements of this sorted multiset. + /** Builds a new sorted bag by applying a function to all elements of this sorted bag. * * @param f the function to apply to each element. * @tparam B the element type of the returned collection. * @return a new collection resulting from applying the given function - * `f` to each element of this sorted multiset and collecting the results. + * `f` to each element of this sorted bag and collecting the results. */ def map[B : Ordering](f: A => B): CC[B] = sortedFromIterable(new View.Map(toIterable, f)) /** - * Builds a new sorted multiset by applying a function to all pairs of element and its + * Builds a new sorted bag by applying a function to all pairs of element and its * number of occurrences. * * @param f the function to apply * @tparam B the element type of the returned collection * @return a new collection resulting from applying the given function * `f` to each pair of element and its number of occurrences of this - * sorted multiset and collecting the results. + * sorted bag and collecting the results. */ def mapOccurrences[B : Ordering](f: ((A, Int)) => (B, Int)): CC[B] = sortedFromOccurrences(new View.Map(occurrences, f)) /** * Builds a new collection by applying a function to all elements of this sorted - * multiset and using the elements of the resulting collections. + * bag and using the elements of the resulting collections. * * @param f the function to apply to each element. * @tparam B the element type of the returned collection. * @return a new collection resulting from applying the given function `f` to - * each element of this sorted multiset and concatenating the results. + * each element of this sorted bag and concatenating the results. */ def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedFromIterable(new View.FlatMap(toIterable, f)) /** * Builds a new collection by applying a function to all pairs of element and - * its number of occurrences of this sorted multiset and using the elements of + * its number of occurrences of this sorted bag and using the elements of * the resulting collections. * * @param f the function to apply to each element. * @tparam B the element type of the returned collection. * @return a new collection resulting from applying the given function `f` to * each pair of element and its number of occurrences of this sorted - * multiset and concatenating the results. + * bag and concatenating the results. */ def flatMapOccurrences[B : Ordering](f: ((A, Int)) => IterableOnce[(B, Int)]): CC[B] = sortedFromOccurrences(new View.FlatMap(occurrences, f)) /** - * Returns a sorted multiset formed from this sorted multiset and another iterable + * Returns a sorted bag formed from this sorted bag and another iterable * collection, by combining corresponding elements in pairs. * @param that The iterable providing the second half of each result pair * @param ev The ordering instance for type `B` * @tparam B the type of the second half of the returned pairs - * @return a new sorted multiset containing pairs consisting of corresponding elements - * of this sorted multiset and `that`. The length of the returned collection + * @return a new sorted bag containing pairs consisting of corresponding elements + * of this sorted bag and `that`. The length of the returned collection * is the minimum of the lengths of `this` and `that` */ def zip[B](that: Iterable[B])(implicit ev: Ordering[B]): CC[(A @uncheckedVariance, B)] = // sound bcs of VarianceNote @@ -124,7 +124,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @return a new collection resulting from applying the given partial * function `pf` to each element on which it is defined and * collecting the results - * @param pf the partial function which filters and map this sorted multiset + * @param pf the partial function which filters and map this sorted bag * @tparam B the element type of the returned collection */ def collect[B : Ordering](pf: PartialFunction[A, B]): CC[B] = flatMap(a => @@ -136,7 +136,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @return a new collection resulting from applying the given partial * function `pf` to each group of occurrences on which it is defined and * collecting the results - * @param pf the partial function which filters and map this sorted multiset + * @param pf the partial function which filters and map this sorted bag * @tparam B the element type of the returned collection */ def collectOccurrences[B : Ordering](pf: PartialFunction[(A, Int), (B, Int)]): CC[B] = flatMapOccurrences(a => @@ -144,21 +144,21 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] else View.Empty ) - // --- Override return type of methods that returned an unsorted MultiSet + // --- Override return type of methods that returned an unsorted Bag override def zipWithIndex: CC[(A, Int)] = sortedFromIterable(new View.ZipWithIndex(toIterable))(Ordering.Tuple2(ordering, implicitly)) } -object SortedMultiSetOps { +object SortedBagOps { /** Specialize `WithFilter` for sorted collections * * @define coll sorted collection */ - class WithFilter[A, +IterableCC[_], +CC[X] <: MultiSet[X]]( - `this`: SortedMultiSetOps[A, CC, _] with IterableOps[A, IterableCC, _], + class WithFilter[A, +IterableCC[_], +CC[X] <: Bag[X]]( + `this`: SortedBagOps[A, CC, _] with IterableOps[A, IterableCC, _], p: A => Boolean ) extends IterableOps.WithFilter[A, IterableCC](`this`, p) { @@ -175,4 +175,4 @@ object SortedMultiSetOps { } -object SortedMultiSet extends SortedIterableFactory.Delegate(immutable.SortedMultiSet) +object SortedBag extends SortedIterableFactory.Delegate(immutable.SortedBag) diff --git a/src/main/scala/scala/collection/SortedMultiDict.scala b/src/main/scala/scala/collection/SortedMultiDict.scala index 9351cc6..20cc104 100644 --- a/src/main/scala/scala/collection/SortedMultiDict.scala +++ b/src/main/scala/scala/collection/SortedMultiDict.scala @@ -69,7 +69,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, * @tparam L the type of keys of the returned collection * @return a new collection resulting from applying the given function * `f` to each pair of element and its number of occurrences of this - * sorted multiset and collecting the results. + * sorted multidict and collecting the results. */ def mapSets[L : Ordering, W](f: ((K, Set[V])) => (L, Set[W])): CC[L, W] = sortedFromSets(new View.Map(sets, f)) diff --git a/src/main/scala/scala/collection/immutable/Bag.scala b/src/main/scala/scala/collection/immutable/Bag.scala new file mode 100644 index 0000000..dfa1ec6 --- /dev/null +++ b/src/main/scala/scala/collection/immutable/Bag.scala @@ -0,0 +1,92 @@ +package scala +package collection +package immutable + +import scala.collection.mutable.{Builder, ImmutableBuilder} + +/** + * An immutable bag + * @tparam A the element type of the collection + */ +trait Bag[A] + extends collection.Bag[A] + with Iterable[A] + with BagOps[A, Bag, Bag[A]] { + + override def iterableFactory: IterableFactory[Bag] = Bag + override protected def fromSpecific(coll: IterableOnce[A]): Bag[A] = iterableFactory.from(coll) + override protected def newSpecificBuilder: mutable.Builder[A, Bag[A]] = iterableFactory.newBuilder + override def empty: Bag[A] = iterableFactory.empty + +} + +trait BagOps[A, +CC[X] <: Bag[X], +C <: Bag[A]] extends collection.BagOps[A, CC, C] { + /** + * @return an immutable bag containing all the elements of this bag + * and one more occurrence of `elem` + * @param elem the element to add + */ + def incl(elem: A): C + + /** Alias for `incl` */ + @`inline` final def + (elem: A): C = incl(elem) + + /** + * @return an immutable bag containing all the elements of this bag + * and one occurrence less of `elem` + * + * @param elem the element to remove + */ + def excl(elem: A): C + + /** Alias for `excl` */ + @`inline` final def - (elem: A): C = excl(elem) +} + +class BagImpl[A] private[immutable](elems: Map[A, Int]) extends Bag[A] { + + def occurrences: Map[A, Int] = elems + + override def iterableFactory: IterableFactory[Bag] = Bag + + /** + * @return an immutable bag containing all the elements of this bag + * and one more occurrence of `elem` + * @param elem the element to add + */ + def incl(elem: A): Bag[A] = + new BagImpl(elems.updatedWith(elem) { + case None => Some(1) + case Some(n) => Some(n + 1) + }) + + /** + * @return an immutable bag containing all the elements of this bag + * and one occurrence less of `elem` + * + * @param elem the element to remove + */ + def excl(elem: A): Bag[A] = + new BagImpl(elems.updatedWith(elem) { + case Some(n) => if (n > 1) Some(n - 1) else None + case None => None + }) + +} + +object Bag extends IterableFactory[Bag] { + + def from[A](source: IterableOnce[A]): Bag[A] = + source match { + case ms: Bag[A] => ms + case _ => (newBuilder[A] ++= source).result() + } + + def empty[A] = new BagImpl[A](Map.empty) + + def newBuilder[A]: Builder[A, Bag[A]] = + new ImmutableBuilder[A, Bag[A]](empty[A]) { + def addOne(elem: A): this.type = { elems = elems + elem; this } + } + +} diff --git a/src/main/scala/scala/collection/immutable/MultiDict.scala b/src/main/scala/scala/collection/immutable/MultiDict.scala index 1a750ae..dee42af 100644 --- a/src/main/scala/scala/collection/immutable/MultiDict.scala +++ b/src/main/scala/scala/collection/immutable/MultiDict.scala @@ -73,7 +73,7 @@ object MultiDict extends MapFactory[MultiDict] { case _ => (newBuilder[K, V] ++= source).result() } - def newBuilder[K, V]: Builder[(K, V), MultiDict[K, V]] = + def newBuilder[K, V]: mutable.Builder[(K, V), MultiDict[K, V]] = new ImmutableBuilder[(K, V), MultiDict[K, V]](empty[K, V]) { def addOne(elem: (K, V)): this.type = { elems = elems + elem; this } } diff --git a/src/main/scala/scala/collection/immutable/MultiSet.scala b/src/main/scala/scala/collection/immutable/MultiSet.scala deleted file mode 100644 index 14d0b80..0000000 --- a/src/main/scala/scala/collection/immutable/MultiSet.scala +++ /dev/null @@ -1,92 +0,0 @@ -package scala -package collection -package immutable - -import scala.collection.mutable.{Builder, ImmutableBuilder} - -/** - * An immutable multiset - * @tparam A the element type of the collection - */ -trait MultiSet[A] - extends collection.MultiSet[A] - with Iterable[A] - with MultiSetOps[A, MultiSet, MultiSet[A]] { - - override def iterableFactory: IterableFactory[MultiSet] = MultiSet - override protected def fromSpecific(coll: IterableOnce[A]): MultiSet[A] = iterableFactory.from(coll) - override protected def newSpecificBuilder: mutable.Builder[A, MultiSet[A]] = iterableFactory.newBuilder - override def empty: MultiSet[A] = iterableFactory.empty - -} - -trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] extends collection.MultiSetOps[A, CC, C] { - /** - * @return an immutable multiset containing all the elements of this multiset - * and one more occurrence of `elem` - * @param elem the element to add - */ - def incl(elem: A): C - - /** Alias for `incl` */ - @`inline` final def + (elem: A): C = incl(elem) - - /** - * @return an immutable multiset containing all the elements of this multiset - * and one occurrence less of `elem` - * - * @param elem the element to remove - */ - def excl(elem: A): C - - /** Alias for `excl` */ - @`inline` final def - (elem: A): C = excl(elem) -} - -class MultiSetImpl[A] private[immutable] (elems: Map[A, Int]) extends MultiSet[A] { - - def occurrences: Map[A, Int] = elems - - override def iterableFactory: IterableFactory[MultiSet] = MultiSet - - /** - * @return an immutable multiset containing all the elements of this multiset - * and one more occurrence of `elem` - * @param elem the element to add - */ - def incl(elem: A): MultiSet[A] = - new MultiSetImpl(elems.updatedWith(elem) { - case None => Some(1) - case Some(n) => Some(n + 1) - }) - - /** - * @return an immutable multiset containing all the elements of this multiset - * and one occurrence less of `elem` - * - * @param elem the element to remove - */ - def excl(elem: A): MultiSet[A] = - new MultiSetImpl(elems.updatedWith(elem) { - case Some(n) => if (n > 1) Some(n - 1) else None - case None => None - }) - -} - -object MultiSet extends IterableFactory[MultiSet] { - - def from[A](source: IterableOnce[A]): MultiSet[A] = - source match { - case ms: MultiSet[A] => ms - case _ => (newBuilder[A] ++= source).result() - } - - def empty[A] = new MultiSetImpl[A](Map.empty) - - def newBuilder[A]: Builder[A, MultiSet[A]] = - new ImmutableBuilder[A, MultiSet[A]](empty[A]) { - def addOne(elem: A): this.type = { elems = elems + elem; this } - } - -} diff --git a/src/main/scala/scala/collection/immutable/SortedBag.scala b/src/main/scala/scala/collection/immutable/SortedBag.scala new file mode 100644 index 0000000..065a915 --- /dev/null +++ b/src/main/scala/scala/collection/immutable/SortedBag.scala @@ -0,0 +1,69 @@ +package scala +package collection +package immutable + +import scala.collection.mutable.{Builder, ImmutableBuilder} + +/** + * An immutable bag whose elements are sorted. + * @tparam A Type of elements + */ +class SortedBag[A] private(elems: SortedMap[A, Int])(implicit val ordering: Ordering[A]) + extends Bag[A] + with collection.SortedBag[A] + with BagOps[A, Bag, SortedBag[A]] + with collection.SortedBagOps[A, SortedBag, SortedBag[A]] + with collection.IterableOps[A, Bag, SortedBag[A]] { + + def occurrences: SortedMap[A, Int] = elems + + override def sortedIterableFactory: SortedIterableFactory[SortedBag] = SortedBag + override protected def fromSpecific(coll: IterableOnce[A]): SortedBag[A] = sortedIterableFactory.from(coll) + override protected def newSpecificBuilder: mutable.Builder[A, SortedBag[A]] = sortedIterableFactory.newBuilder[A] + override def empty: SortedBag[A] = sortedIterableFactory.empty + override def withFilter(p: A => Boolean): SortedBagOps.WithFilter[A, Bag, SortedBag] = + new SortedBagOps.WithFilter(this, p) + + def rangeImpl(from: Option[A], until: Option[A]): SortedBag[A] = + new SortedBag(elems.rangeImpl(from, until)) + + /** + * @return an immutable sorted bag containing all the elements of + * this bag and one more occurrence of `elem` + * @param elem the element to add + */ + def incl(elem: A): SortedBag[A] = + new SortedBag(elems.updatedWith(elem) { + case None => Some(1) + case Some(n) => Some(n + 1) + }) + + /** + * @return an immutable sorted bag containing all the elements of + * this bag and one occurrence less of `elem` + * + * @param elem the element to remove + */ + def excl(elem: A): SortedBag[A] = + new SortedBag(elems.updatedWith(elem) { + case Some(n) => if (n > 1) Some(n - 1) else None + case None => None + }) +} + +object SortedBag extends SortedIterableFactory[SortedBag] { + + def from[A: Ordering](source: IterableOnce[A]): SortedBag[A] = + source match { + case sms: SortedBag[A] => sms + case _ => (newBuilder[A] ++= source).result() + } + + def empty[A: Ordering]: SortedBag[A] = new SortedBag[A](TreeMap.empty) + + def newBuilder[A: Ordering]: Builder[A, SortedBag[A]] = + new ImmutableBuilder[A, SortedBag[A]](empty) { + def addOne(elem: A): this.type = { elems = elems + elem; this } + } + +} \ No newline at end of file diff --git a/src/main/scala/scala/collection/immutable/SortedMultiSet.scala b/src/main/scala/scala/collection/immutable/SortedMultiSet.scala deleted file mode 100644 index c1d593f..0000000 --- a/src/main/scala/scala/collection/immutable/SortedMultiSet.scala +++ /dev/null @@ -1,69 +0,0 @@ -package scala -package collection -package immutable - -import scala.collection.mutable.{Builder, ImmutableBuilder} - -/** - * An immutable multiset whose elements are sorted. - * @tparam A Type of elements - */ -class SortedMultiSet[A] private (elems: SortedMap[A, Int])(implicit val ordering: Ordering[A]) - extends MultiSet[A] - with collection.SortedMultiSet[A] - with MultiSetOps[A, MultiSet, SortedMultiSet[A]] - with collection.SortedMultiSetOps[A, SortedMultiSet, SortedMultiSet[A]] - with collection.IterableOps[A, MultiSet, SortedMultiSet[A]] { - - def occurrences: SortedMap[A, Int] = elems - - override def sortedIterableFactory: SortedIterableFactory[SortedMultiSet] = SortedMultiSet - override protected def fromSpecific(coll: IterableOnce[A]): SortedMultiSet[A] = sortedIterableFactory.from(coll) - override protected def newSpecificBuilder: mutable.Builder[A, SortedMultiSet[A]] = sortedIterableFactory.newBuilder[A] - override def empty: SortedMultiSet[A] = sortedIterableFactory.empty - override def withFilter(p: A => Boolean): SortedMultiSetOps.WithFilter[A, MultiSet, SortedMultiSet] = - new SortedMultiSetOps.WithFilter(this, p) - - def rangeImpl(from: Option[A], until: Option[A]): SortedMultiSet[A] = - new SortedMultiSet(elems.rangeImpl(from, until)) - - /** - * @return an immutable sorted multiset containing all the elements of - * this multiset and one more occurrence of `elem` - * @param elem the element to add - */ - def incl(elem: A): SortedMultiSet[A] = - new SortedMultiSet(elems.updatedWith(elem) { - case None => Some(1) - case Some(n) => Some(n + 1) - }) - - /** - * @return an immutable sorted multiset containing all the elements of - * this multiset and one occurrence less of `elem` - * - * @param elem the element to remove - */ - def excl(elem: A): SortedMultiSet[A] = - new SortedMultiSet(elems.updatedWith(elem) { - case Some(n) => if (n > 1) Some(n - 1) else None - case None => None - }) -} - -object SortedMultiSet extends SortedIterableFactory[SortedMultiSet] { - - def from[A: Ordering](source: IterableOnce[A]): SortedMultiSet[A] = - source match { - case sms: SortedMultiSet[A] => sms - case _ => (newBuilder[A] ++= source).result() - } - - def empty[A: Ordering]: SortedMultiSet[A] = new SortedMultiSet[A](TreeMap.empty) - - def newBuilder[A: Ordering]: Builder[A, SortedMultiSet[A]] = - new ImmutableBuilder[A, SortedMultiSet[A]](empty) { - def addOne(elem: A): this.type = { elems = elems + elem; this } - } - -} \ No newline at end of file diff --git a/src/main/scala/scala/collection/mutable/Bag.scala b/src/main/scala/scala/collection/mutable/Bag.scala new file mode 100644 index 0000000..fd78d5a --- /dev/null +++ b/src/main/scala/scala/collection/mutable/Bag.scala @@ -0,0 +1,53 @@ +package scala +package collection +package mutable + +/** + * A mutable bag. + */ +trait Bag[A] + extends collection.Bag[A] + with collection.BagOps[A, Bag, Bag[A]] + with Growable[A] + with Shrinkable [A] { + + override def iterableFactory: IterableFactory[Bag] = Bag + override protected def fromSpecific(coll: IterableOnce[A]): Bag[A] = iterableFactory.from(coll) + override protected def newSpecificBuilder: mutable.Builder[A, Bag[A]] = iterableFactory.newBuilder + override def empty: Bag[A] = iterableFactory.empty + + override def knownSize = super[Growable].knownSize +} + +class BagImpl[A] private[mutable](val elems: Map[A, Int]) extends Bag[A] { + + def occurrences: collection.Map[A, Int] = elems + + def addOne(elem: A): this.type = { + elems.updateWith(elem) { + case None => Some(1) + case Some(n) => Some(n + 1) + } + this + } + + def subtractOne(elem: A): this.type = { + elems.updateWith(elem) { + case Some(n) => if (n > 1) Some(n - 1) else None + case None => None + } + this + } + + def clear(): Unit = elems.clear() +} + +object Bag extends IterableFactory[Bag] { + + def from[A](source: IterableOnce[A]): Bag[A] = (newBuilder[A] ++= source).result() + + def empty[A]: Bag[A] = new BagImpl[A](Map.empty) + + def newBuilder[A]: Builder[A, Bag[A]] = new GrowableBuilder[A, Bag[A]](empty) + +} \ No newline at end of file diff --git a/src/main/scala/scala/collection/mutable/MultiSet.scala b/src/main/scala/scala/collection/mutable/MultiSet.scala deleted file mode 100644 index e2098a8..0000000 --- a/src/main/scala/scala/collection/mutable/MultiSet.scala +++ /dev/null @@ -1,53 +0,0 @@ -package scala -package collection -package mutable - -/** - * A mutable multiset. - */ -trait MultiSet[A] - extends collection.MultiSet[A] - with collection.MultiSetOps[A, MultiSet, MultiSet[A]] - with Growable[A] - with Shrinkable [A] { - - override def iterableFactory: IterableFactory[MultiSet] = MultiSet - override protected def fromSpecific(coll: IterableOnce[A]): MultiSet[A] = iterableFactory.from(coll) - override protected def newSpecificBuilder: mutable.Builder[A, MultiSet[A]] = iterableFactory.newBuilder - override def empty: MultiSet[A] = iterableFactory.empty - - override def knownSize = super[Growable].knownSize -} - -class MultiSetImpl[A] private[mutable] (val elems: Map[A, Int]) extends MultiSet[A] { - - def occurrences: collection.Map[A, Int] = elems - - def addOne(elem: A): this.type = { - elems.updateWith(elem) { - case None => Some(1) - case Some(n) => Some(n + 1) - } - this - } - - def subtractOne(elem: A): this.type = { - elems.updateWith(elem) { - case Some(n) => if (n > 1) Some(n - 1) else None - case None => None - } - this - } - - def clear(): Unit = elems.clear() -} - -object MultiSet extends IterableFactory[MultiSet] { - - def from[A](source: IterableOnce[A]): MultiSet[A] = (newBuilder[A] ++= source).result() - - def empty[A]: MultiSet[A] = new MultiSetImpl[A](Map.empty) - - def newBuilder[A]: Builder[A, MultiSet[A]] = new GrowableBuilder[A, MultiSet[A]](empty) - -} \ No newline at end of file diff --git a/src/main/scala/scala/collection/mutable/SortedBag.scala b/src/main/scala/scala/collection/mutable/SortedBag.scala new file mode 100644 index 0000000..b8d4c9d --- /dev/null +++ b/src/main/scala/scala/collection/mutable/SortedBag.scala @@ -0,0 +1,57 @@ +package scala +package collection +package mutable + +/** + * A mutable bag whose elements are sorted according to a given ordering. + * + * @tparam A Type of elements + */ +class SortedBag[A] private(elems: SortedMap[A, Int])(implicit val ordering: Ordering[A]) + extends Bag[A] + with collection.SortedBag[A] + with collection.SortedBagOps[A, SortedBag, SortedBag[A]] + with BagOps[A, Bag, SortedBag[A]] + with Growable[A] + with Shrinkable[A] { + + def occurrences: collection.SortedMap[A, Int] = elems + + override def sortedIterableFactory: SortedIterableFactory[SortedBag] = SortedBag + override protected def fromSpecific(coll: IterableOnce[A]): SortedBag[A] = sortedIterableFactory.from(coll) + override protected def newSpecificBuilder: mutable.Builder[A, SortedBag[A]] = sortedIterableFactory.newBuilder[A] + override def empty: SortedBag[A] = sortedIterableFactory.empty + override def withFilter(p: A => Boolean): SortedBagOps.WithFilter[A, Bag, SortedBag] = + new SortedBagOps.WithFilter(this, p) + + def rangeImpl(from: Option[A], until: Option[A]): SortedBag[A] = + new SortedBag(elems.rangeImpl(from, until)) + + def addOne(elem: A): this.type = { + elems.updateWith(elem) { + case None => Some(1) + case Some(n) => Some(n + 1) + } + this + } + + def subtractOne(elem: A): this.type = { + elems.updateWith(elem) { + case Some(n) => if (n > 1) Some(n - 1) else None + case None => None + } + this + } + + def clear(): Unit = elems.clear() +} + +object SortedBag extends SortedIterableFactory[SortedBag] { + + def from[E: Ordering](it: IterableOnce[E]): SortedBag[E] = (newBuilder[E] ++= it).result() + + def empty[A: Ordering]: SortedBag[A] = new SortedBag[A](SortedMap.empty[A, Int]) + + def newBuilder[A: Ordering]: Builder[A, SortedBag[A]] = new GrowableBuilder[A, SortedBag[A]](empty) + +} \ No newline at end of file diff --git a/src/main/scala/scala/collection/mutable/SortedMultiSet.scala b/src/main/scala/scala/collection/mutable/SortedMultiSet.scala deleted file mode 100644 index 1bc1667..0000000 --- a/src/main/scala/scala/collection/mutable/SortedMultiSet.scala +++ /dev/null @@ -1,57 +0,0 @@ -package scala -package collection -package mutable - -/** - * A mutable multiset whose elements are sorted according to a given ordering. - * - * @tparam A Type of elements - */ -class SortedMultiSet[A] private (elems: SortedMap[A, Int])(implicit val ordering: Ordering[A]) - extends MultiSet[A] - with collection.SortedMultiSet[A] - with collection.SortedMultiSetOps[A, SortedMultiSet, SortedMultiSet[A]] - with MultiSetOps[A, MultiSet, SortedMultiSet[A]] - with Growable[A] - with Shrinkable[A] { - - def occurrences: collection.SortedMap[A, Int] = elems - - override def sortedIterableFactory: SortedIterableFactory[SortedMultiSet] = SortedMultiSet - override protected def fromSpecific(coll: IterableOnce[A]): SortedMultiSet[A] = sortedIterableFactory.from(coll) - override protected def newSpecificBuilder: mutable.Builder[A, SortedMultiSet[A]] = sortedIterableFactory.newBuilder[A] - override def empty: SortedMultiSet[A] = sortedIterableFactory.empty - override def withFilter(p: A => Boolean): SortedMultiSetOps.WithFilter[A, MultiSet, SortedMultiSet] = - new SortedMultiSetOps.WithFilter(this, p) - - def rangeImpl(from: Option[A], until: Option[A]): SortedMultiSet[A] = - new SortedMultiSet(elems.rangeImpl(from, until)) - - def addOne(elem: A): this.type = { - elems.updateWith(elem) { - case None => Some(1) - case Some(n) => Some(n + 1) - } - this - } - - def subtractOne(elem: A): this.type = { - elems.updateWith(elem) { - case Some(n) => if (n > 1) Some(n - 1) else None - case None => None - } - this - } - - def clear(): Unit = elems.clear() -} - -object SortedMultiSet extends SortedIterableFactory[SortedMultiSet] { - - def from[E: Ordering](it: IterableOnce[E]): SortedMultiSet[E] = (newBuilder[E] ++= it).result() - - def empty[A: Ordering]: SortedMultiSet[A] = new SortedMultiSet[A](SortedMap.empty[A, Int]) - - def newBuilder[A: Ordering]: Builder[A, SortedMultiSet[A]] = new GrowableBuilder[A, SortedMultiSet[A]](empty) - -} \ No newline at end of file diff --git a/src/test/scala/scala/collection/MultiSetTest.scala b/src/test/scala/scala/collection/BagTest.scala similarity index 50% rename from src/test/scala/scala/collection/MultiSetTest.scala rename to src/test/scala/scala/collection/BagTest.scala index 143e92a..aab7821 100644 --- a/src/test/scala/scala/collection/MultiSetTest.scala +++ b/src/test/scala/scala/collection/BagTest.scala @@ -6,12 +6,12 @@ import scala.collection.immutable.List import org.junit.{Assert, Test} @RunWith(classOf[JUnit4]) -class MultiSetTest { +class BagTest { @Test def equality(): Unit = { - val ms1 = MultiSet("a", "b", "b", "c") - val ms2 = MultiSet("a", "b", "b", "c") + val ms1 = Bag("a", "b", "b", "c") + val ms2 = Bag("a", "b", "b", "c") Assert.assertEquals(ms2, ms1) Assert.assertEquals(ms1, ms2) @@ -21,43 +21,43 @@ class MultiSetTest { @Test def concat(): Unit = { Assert.assertEquals( - MultiSet(1, 1), - MultiSet(1).concat(MultiSet(1)) + Bag(1, 1), + Bag(1).concat(Bag(1)) ) Assert.assertEquals( - MultiSet("a", "a", "a"), - MultiSet("a").concatOccurrences(List(("a", 2))) + Bag("a", "a", "a"), + Bag("a").concatOccurrences(List(("a", 2))) ) } @Test def map(): Unit = { Assert.assertEquals( - MultiSet("A", "B", "B"), - MultiSet("a", "b", "b").map(_.toUpperCase) + Bag("A", "B", "B"), + Bag("a", "b", "b").map(_.toUpperCase) ) Assert.assertEquals( - MultiSet(1, 1), - MultiSet("a", "b").map(_ => 1) + Bag(1, 1), + Bag("a", "b").map(_ => 1) ) Assert.assertEquals( - MultiSet("c", "c", "c", "c"), - MultiSet("a", "b", "b").mapOccurrences { _ => ("c", 2) } + Bag("c", "c", "c", "c"), + Bag("a", "b", "b").mapOccurrences { _ => ("c", 2) } ) } @Test def testToString(): Unit = { - def run(ms: MultiSet[Int]): Unit = { + def run(ms: Bag[Int]): Unit = { val actual = ms.toString - assert(actual.startsWith("MultiSet("), s"`$actual` does not start with `MultiSet(`") + assert(actual.startsWith("Bag("), s"`$actual` does not start with `Bag(`") assert(actual.endsWith(")"), s"`$actual` does not end with `)`") - // The order of elements in the multiset are not defined, so this test should be robust to order changes + // The order of elements in the bag are not defined, so this test should be robust to order changes Assert.assertEquals(ms, actual - .stripPrefix("MultiSet(") + .stripPrefix("Bag(") .stripSuffix(")") .split(",") .iterator @@ -65,12 +65,12 @@ class MultiSetTest { case "" => None case s => Some(s.toInt) }) - .to(MultiSet)) + .to(Bag)) } - def runForFactory(factory: IterableFactory[MultiSet]): Unit = { - Assert.assertEquals(factory().toString, "MultiSet()") - Assert.assertEquals(factory(1).toString, "MultiSet(1)") + def runForFactory(factory: IterableFactory[Bag]): Unit = { + Assert.assertEquals(factory().toString, "Bag()") + Assert.assertEquals(factory(1).toString, "Bag(1)") run(factory()) run(factory(1)) @@ -80,9 +80,9 @@ class MultiSetTest { run(factory(1,1,1,2,2,2,2,3)) } - runForFactory(MultiSet) - runForFactory(mutable.MultiSet) - runForFactory(immutable.MultiSet) + runForFactory(Bag) + runForFactory(mutable.Bag) + runForFactory(immutable.Bag) } } diff --git a/src/test/scala/scala/collection/MultiDictTest.scala b/src/test/scala/scala/collection/MultiDictTest.scala index c0a5efe..262a48f 100644 --- a/src/test/scala/scala/collection/MultiDictTest.scala +++ b/src/test/scala/scala/collection/MultiDictTest.scala @@ -83,7 +83,7 @@ class MultiDictTest { assert(actual.startsWith(prefix), s"`$actual` does not start with `$prefix`") assert(actual.endsWith(suffix), s"`$actual` does not end with `$suffix`") - // The order of elements in the multiset are not defined, so this test should be robust to order changes + // The order of elements in the bag are not defined, so this test should be robust to order changes val expected = actual diff --git a/src/test/scala/scala/collection/SortedMultiSetTest.scala b/src/test/scala/scala/collection/SortedBagTest.scala similarity index 57% rename from src/test/scala/scala/collection/SortedMultiSetTest.scala rename to src/test/scala/scala/collection/SortedBagTest.scala index 4383a49..d51d700 100644 --- a/src/test/scala/scala/collection/SortedMultiSetTest.scala +++ b/src/test/scala/scala/collection/SortedBagTest.scala @@ -6,19 +6,19 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(classOf[JUnit4]) -class SortedMultiSetTest { +class SortedBagTest { - def sortedMultiSet(sms: SortedMultiSet[Int]): Unit = { + def sortedBag(sms: SortedBag[Int]): Unit = { Assert.assertEquals(1, sms.get(1)) Assert.assertEquals(2, sms.get(2)) Assert.assertEquals(1, sms.firstKey) Assert.assertEquals(3, sms.lastKey) - Assert.assertEquals(SortedMultiSet(3, 2, 2), sms.rangeFrom(2)) + Assert.assertEquals(SortedBag(3, 2, 2), sms.rangeFrom(2)) } @Test def run(): Unit = { - sortedMultiSet(immutable.SortedMultiSet(2, 1, 3, 2)) - sortedMultiSet(mutable.SortedMultiSet(2, 1, 3, 2)) + sortedBag(immutable.SortedBag(2, 1, 3, 2)) + sortedBag(mutable.SortedBag(2, 1, 3, 2)) } } diff --git a/src/test/scala/scala/collection/immutable/MultiSetTest.scala b/src/test/scala/scala/collection/immutable/BagTest.scala similarity index 87% rename from src/test/scala/scala/collection/immutable/MultiSetTest.scala rename to src/test/scala/scala/collection/immutable/BagTest.scala index fa7c99e..9a74c20 100644 --- a/src/test/scala/scala/collection/immutable/MultiSetTest.scala +++ b/src/test/scala/scala/collection/immutable/BagTest.scala @@ -5,11 +5,11 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(classOf[JUnit4]) -class MultiSetTest { +class BagTest { @Test - def multiSet(): Unit = { - val ms = MultiSet("a", "b", "b", "c") + def bag(): Unit = { + val ms = Bag("a", "b", "b", "c") val m = Map("a" -> 1, "b" -> 2, "c" -> 1) Assert.assertEquals(m, ms.occurrences) Assert.assertEquals(ms.occurrences, m) diff --git a/src/test/scala/scala/collection/immutable/MultiMapTest.scala b/src/test/scala/scala/collection/immutable/MultiDictTest.scala similarity index 97% rename from src/test/scala/scala/collection/immutable/MultiMapTest.scala rename to src/test/scala/scala/collection/immutable/MultiDictTest.scala index 4f906c0..c6059cd 100644 --- a/src/test/scala/scala/collection/immutable/MultiMapTest.scala +++ b/src/test/scala/scala/collection/immutable/MultiDictTest.scala @@ -5,7 +5,7 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(classOf[JUnit4]) -class MultiMapTest { +class MultiDictTest { @Test def multiMap(): Unit = { diff --git a/src/test/scala/scala/collection/immutable/SortedMultiSetTest.scala b/src/test/scala/scala/collection/immutable/SortedBagTest.scala similarity index 73% rename from src/test/scala/scala/collection/immutable/SortedMultiSetTest.scala rename to src/test/scala/scala/collection/immutable/SortedBagTest.scala index e7108f2..b6592e7 100644 --- a/src/test/scala/scala/collection/immutable/SortedMultiSetTest.scala +++ b/src/test/scala/scala/collection/immutable/SortedBagTest.scala @@ -5,16 +5,16 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(classOf[JUnit4]) -class SortedMultiSetTest { +class SortedBagTest { @Test - def sortedMultiSet(): Unit = { - val sms = SortedMultiSet(2, 1, 3, 2) + def sortedBag(): Unit = { + val sms = SortedBag(2, 1, 3, 2) Assert.assertEquals(1, sms.get(1)) Assert.assertEquals(2, sms.get(2)) Assert.assertEquals(1, sms.firstKey) Assert.assertEquals(3, sms.lastKey) - Assert.assertEquals(SortedMultiSet(3, 2, 2), sms.rangeFrom(2)) + Assert.assertEquals(SortedBag(3, 2, 2), sms.rangeFrom(2)) val sms2 = sms + 2 Assert.assertEquals(3, sms2.get(2)) val sms3 = sms2 - 3 diff --git a/src/test/scala/scala/collection/immutable/SortedMultiMapTest.scala b/src/test/scala/scala/collection/immutable/SortedMultiDictTest.scala similarity index 97% rename from src/test/scala/scala/collection/immutable/SortedMultiMapTest.scala rename to src/test/scala/scala/collection/immutable/SortedMultiDictTest.scala index 9ced847..ccd2a80 100644 --- a/src/test/scala/scala/collection/immutable/SortedMultiMapTest.scala +++ b/src/test/scala/scala/collection/immutable/SortedMultiDictTest.scala @@ -5,7 +5,7 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(classOf[JUnit4]) -class SortedMultiMapTest { +class SortedMultiDictTest { @Test def sortedMultiMap(): Unit = { diff --git a/src/test/scala/scala/collection/mutable/MultiSetTest.scala b/src/test/scala/scala/collection/mutable/BagTest.scala similarity index 87% rename from src/test/scala/scala/collection/mutable/MultiSetTest.scala rename to src/test/scala/scala/collection/mutable/BagTest.scala index c470dff..bd35cfb 100644 --- a/src/test/scala/scala/collection/mutable/MultiSetTest.scala +++ b/src/test/scala/scala/collection/mutable/BagTest.scala @@ -7,11 +7,11 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(classOf[JUnit4]) -class MultiSetTest { +class BagTest { @Test - def multiSet(): Unit = { - val ms = MultiSet.empty[String] + def bag(): Unit = { + val ms = Bag.empty[String] ms += "a" ms += "a" diff --git a/src/test/scala/scala/collection/mutable/SortedMultiSetTest.scala b/src/test/scala/scala/collection/mutable/SortedBagTest.scala similarity index 81% rename from src/test/scala/scala/collection/mutable/SortedMultiSetTest.scala rename to src/test/scala/scala/collection/mutable/SortedBagTest.scala index 7b851ec..449748b 100644 --- a/src/test/scala/scala/collection/mutable/SortedMultiSetTest.scala +++ b/src/test/scala/scala/collection/mutable/SortedBagTest.scala @@ -5,11 +5,11 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 @RunWith(classOf[JUnit4]) -class SortedMultiSetTest { +class SortedBagTest { @Test - def sortedMultiSet(): Unit = { - val sms = SortedMultiSet(2, 1, 3, 2) + def sortedBag(): Unit = { + val sms = SortedBag(2, 1, 3, 2) Assert.assertEquals(1, sms.get(1)) Assert.assertEquals(2, sms.get(2)) Assert.assertEquals(1, sms.firstKey)