Skip to content

Commit

Permalink
[scala#17] Rename MultiSet to Bag
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh Lemer authored and Josh Lemer committed Oct 16, 2019
1 parent 0a1df6b commit 100b3ad
Show file tree
Hide file tree
Showing 22 changed files with 365 additions and 363 deletions.
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

0 comments on commit 100b3ad

Please sign in to comment.