Skip to content

[#17] Rename MultiSet to Bag #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) && {
Expand All @@ -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 =
Expand Down Expand Up @@ -126,4 +128,4 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]

}

object MultiSet extends IterableFactory.Delegate(immutable.MultiSet)
object Bag extends IterableFactory.Delegate(immutable.Bag)
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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]

Expand Down Expand Up @@ -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
Expand All @@ -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 =>
Expand All @@ -136,29 +136,29 @@ 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 =>
if (pf.isDefinedAt(a)) new View.Single(pf(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) {

Expand All @@ -175,4 +175,4 @@ object SortedMultiSetOps {

}

object SortedMultiSet extends SortedIterableFactory.Delegate(immutable.SortedMultiSet)
object SortedBag extends SortedIterableFactory.Delegate(immutable.SortedBag)
2 changes: 1 addition & 1 deletion src/main/scala/scala/collection/SortedMultiDict.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
92 changes: 92 additions & 0 deletions src/main/scala/scala/collection/immutable/Bag.scala
Original file line number Diff line number Diff line change
@@ -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 }
}

}
2 changes: 1 addition & 1 deletion src/main/scala/scala/collection/immutable/MultiDict.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
Expand Down
Loading