Skip to content

Commit b87bd3a

Browse files
committed
[scala#17] Rename MultiSet to Bag
1 parent 22bb87a commit b87bd3a

22 files changed

+365
-363
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ This module provides extra features to the Scala standard collections.
44

55
## New Collection Types
66

7-
- `MultiSet` (both mutable and immutable)
8-
- `SortedMultiSet` (both mutable and immutable)
7+
- `Bag` (both mutable and immutable)
8+
- `SortedBag` (both mutable and immutable)
99
- `MultiDict` (both mutable and immutable)
1010
- `SortedMultiDict` (both mutable and immutable)
1111

src/main/scala/scala/collection/MultiSet.scala renamed to src/main/scala/scala/collection/Bag.scala

+13-11
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,28 @@ package scala.collection
33
import scala.util.hashing.MurmurHash3
44

55
/**
6-
* A multiset is a set that can contain multiple occurrences of a same value.
6+
* A bag is an unordered collection that can contain multiple occurrences of the same value.
7+
*
8+
* Two bags are defined to be equal if they have the same elements, and the same number of occurrences of each element.
79
*
810
* @tparam A the element type of the collection
911
*/
10-
trait MultiSet[A]
12+
trait Bag[A]
1113
extends Iterable[A]
12-
with MultiSetOps[A, MultiSet, MultiSet[A]]
14+
with BagOps[A, Bag, Bag[A]]
1315
with Equals {
1416

15-
override protected[this] def className: String = "MultiSet"
17+
override protected[this] def className: String = "Bag"
1618

17-
override def iterableFactory: IterableFactory[MultiSet] = MultiSet
18-
override protected def fromSpecific(coll: IterableOnce[A]): MultiSet[A] = iterableFactory.from(coll)
19-
override protected def newSpecificBuilder: mutable.Builder[A, MultiSet[A]] = iterableFactory.newBuilder
20-
override def empty: MultiSet[A] = iterableFactory.empty
19+
override def iterableFactory: IterableFactory[Bag] = Bag
20+
override protected def fromSpecific(coll: IterableOnce[A]): Bag[A] = iterableFactory.from(coll)
21+
override protected def newSpecificBuilder: mutable.Builder[A, Bag[A]] = iterableFactory.newBuilder
22+
override def empty: Bag[A] = iterableFactory.empty
2123

2224
def canEqual(that: Any): Boolean = true
2325

2426
override def equals(o: Any): Boolean = o match {
25-
case that: MultiSet[A] =>
27+
case that: Bag[A] =>
2628
(this eq that) ||
2729
(that canEqual this) &&
2830
(this.size == that.size) && {
@@ -39,7 +41,7 @@ trait MultiSet[A]
3941

4042
}
4143

42-
trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
44+
trait BagOps[A, +CC[X] <: Bag[X], +C <: Bag[A]]
4345
extends IterableOps[A, CC, C] {
4446

4547
protected[this] def fromSpecificOccurrences(it: Iterable[(A, Int)]): C =
@@ -126,4 +128,4 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
126128

127129
}
128130

129-
object MultiSet extends IterableFactory.Delegate(immutable.MultiSet)
131+
object Bag extends IterableFactory.Delegate(immutable.Bag)

src/main/scala/scala/collection/SortedMultiSet.scala renamed to src/main/scala/scala/collection/SortedBag.scala

+32-32
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,25 @@ package scala.collection
33
import scala.annotation.unchecked.uncheckedVariance
44

55
/**
6-
* Multiset whose elements are sorted
6+
* Bag whose elements are sorted
77
* @tparam A Type of elements
88
*/
9-
trait SortedMultiSet[A]
10-
extends MultiSet[A]
11-
with SortedMultiSetOps[A, SortedMultiSet, SortedMultiSet[A]] {
9+
trait SortedBag[A]
10+
extends Bag[A]
11+
with SortedBagOps[A, SortedBag, SortedBag[A]] {
1212

13-
def unsorted: MultiSet[A] = this
13+
def unsorted: Bag[A] = this
1414

15-
def sortedIterableFactory: SortedIterableFactory[SortedMultiSet] = SortedMultiSet
16-
override protected def fromSpecific(coll: IterableOnce[A]): SortedMultiSet[A] = sortedIterableFactory.from(coll)(ordering)
17-
override protected def newSpecificBuilder: mutable.Builder[A, SortedMultiSet[A]] = sortedIterableFactory.newBuilder(ordering)
18-
override def empty: SortedMultiSet[A] = sortedIterableFactory.empty(ordering)
19-
override def withFilter(p: A => Boolean): SortedMultiSetOps.WithFilter[A, MultiSet, SortedMultiSet] = new SortedMultiSetOps.WithFilter(this, p)
15+
def sortedIterableFactory: SortedIterableFactory[SortedBag] = SortedBag
16+
override protected def fromSpecific(coll: IterableOnce[A]): SortedBag[A] = sortedIterableFactory.from(coll)(ordering)
17+
override protected def newSpecificBuilder: mutable.Builder[A, SortedBag[A]] = sortedIterableFactory.newBuilder(ordering)
18+
override def empty: SortedBag[A] = sortedIterableFactory.empty(ordering)
19+
override def withFilter(p: A => Boolean): SortedBagOps.WithFilter[A, Bag, SortedBag] = new SortedBagOps.WithFilter(this, p)
2020

2121
}
2222

23-
trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
24-
extends MultiSetOps[A, MultiSet, C]
23+
trait SortedBagOps[A, +CC[X] <: Bag[X], +C <: Bag[A]]
24+
extends BagOps[A, Bag, C]
2525
with SortedOps[A, C] {
2626

2727
def sortedIterableFactory: SortedIterableFactory[CC]
@@ -30,8 +30,8 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
3030
protected def sortedFromOccurrences[B : Ordering](it: Iterable[(B, Int)]): CC[B] =
3131
sortedFromIterable(it.view.flatMap { case (b, n) => new View.Fill(n)(b) })
3232

33-
/** `this` sorted multiset upcasted to an unsorted multiset */
34-
def unsorted: MultiSet[A]
33+
/** `this` sorted bag upcasted to an unsorted bag */
34+
def unsorted: Bag[A]
3535

3636
def occurrences: SortedMap[A, Int]
3737

@@ -60,61 +60,61 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
6060
rangeUntil(next)
6161
}
6262

63-
/** Builds a new sorted multiset by applying a function to all elements of this sorted multiset.
63+
/** Builds a new sorted bag by applying a function to all elements of this sorted bag.
6464
*
6565
* @param f the function to apply to each element.
6666
* @tparam B the element type of the returned collection.
6767
* @return a new collection resulting from applying the given function
68-
* `f` to each element of this sorted multiset and collecting the results.
68+
* `f` to each element of this sorted bag and collecting the results.
6969
*/
7070
def map[B : Ordering](f: A => B): CC[B] = sortedFromIterable(new View.Map(toIterable, f))
7171

7272
/**
73-
* Builds a new sorted multiset by applying a function to all pairs of element and its
73+
* Builds a new sorted bag by applying a function to all pairs of element and its
7474
* number of occurrences.
7575
*
7676
* @param f the function to apply
7777
* @tparam B the element type of the returned collection
7878
* @return a new collection resulting from applying the given function
7979
* `f` to each pair of element and its number of occurrences of this
80-
* sorted multiset and collecting the results.
80+
* sorted bag and collecting the results.
8181
*/
8282
def mapOccurrences[B : Ordering](f: ((A, Int)) => (B, Int)): CC[B] =
8383
sortedFromOccurrences(new View.Map(occurrences, f))
8484

8585
/**
8686
* Builds a new collection by applying a function to all elements of this sorted
87-
* multiset and using the elements of the resulting collections.
87+
* bag and using the elements of the resulting collections.
8888
*
8989
* @param f the function to apply to each element.
9090
* @tparam B the element type of the returned collection.
9191
* @return a new collection resulting from applying the given function `f` to
92-
* each element of this sorted multiset and concatenating the results.
92+
* each element of this sorted bag and concatenating the results.
9393
*/
9494
def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedFromIterable(new View.FlatMap(toIterable, f))
9595

9696
/**
9797
* Builds a new collection by applying a function to all pairs of element and
98-
* its number of occurrences of this sorted multiset and using the elements of
98+
* its number of occurrences of this sorted bag and using the elements of
9999
* the resulting collections.
100100
*
101101
* @param f the function to apply to each element.
102102
* @tparam B the element type of the returned collection.
103103
* @return a new collection resulting from applying the given function `f` to
104104
* each pair of element and its number of occurrences of this sorted
105-
* multiset and concatenating the results.
105+
* bag and concatenating the results.
106106
*/
107107
def flatMapOccurrences[B : Ordering](f: ((A, Int)) => IterableOnce[(B, Int)]): CC[B] =
108108
sortedFromOccurrences(new View.FlatMap(occurrences, f))
109109

110110
/**
111-
* Returns a sorted multiset formed from this sorted multiset and another iterable
111+
* Returns a sorted bag formed from this sorted bag and another iterable
112112
* collection, by combining corresponding elements in pairs.
113113
* @param that The iterable providing the second half of each result pair
114114
* @param ev The ordering instance for type `B`
115115
* @tparam B the type of the second half of the returned pairs
116-
* @return a new sorted multiset containing pairs consisting of corresponding elements
117-
* of this sorted multiset and `that`. The length of the returned collection
116+
* @return a new sorted bag containing pairs consisting of corresponding elements
117+
* of this sorted bag and `that`. The length of the returned collection
118118
* is the minimum of the lengths of `this` and `that`
119119
*/
120120
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]]
124124
* @return a new collection resulting from applying the given partial
125125
* function `pf` to each element on which it is defined and
126126
* collecting the results
127-
* @param pf the partial function which filters and map this sorted multiset
127+
* @param pf the partial function which filters and map this sorted bag
128128
* @tparam B the element type of the returned collection
129129
*/
130130
def collect[B : Ordering](pf: PartialFunction[A, B]): CC[B] = flatMap(a =>
@@ -136,29 +136,29 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
136136
* @return a new collection resulting from applying the given partial
137137
* function `pf` to each group of occurrences on which it is defined and
138138
* collecting the results
139-
* @param pf the partial function which filters and map this sorted multiset
139+
* @param pf the partial function which filters and map this sorted bag
140140
* @tparam B the element type of the returned collection
141141
*/
142142
def collectOccurrences[B : Ordering](pf: PartialFunction[(A, Int), (B, Int)]): CC[B] = flatMapOccurrences(a =>
143143
if (pf.isDefinedAt(a)) new View.Single(pf(a))
144144
else View.Empty
145145
)
146146

147-
// --- Override return type of methods that returned an unsorted MultiSet
147+
// --- Override return type of methods that returned an unsorted Bag
148148

149149
override def zipWithIndex: CC[(A, Int)] =
150150
sortedFromIterable(new View.ZipWithIndex(toIterable))(Ordering.Tuple2(ordering, implicitly))
151151

152152
}
153153

154-
object SortedMultiSetOps {
154+
object SortedBagOps {
155155

156156
/** Specialize `WithFilter` for sorted collections
157157
*
158158
* @define coll sorted collection
159159
*/
160-
class WithFilter[A, +IterableCC[_], +CC[X] <: MultiSet[X]](
161-
`this`: SortedMultiSetOps[A, CC, _] with IterableOps[A, IterableCC, _],
160+
class WithFilter[A, +IterableCC[_], +CC[X] <: Bag[X]](
161+
`this`: SortedBagOps[A, CC, _] with IterableOps[A, IterableCC, _],
162162
p: A => Boolean
163163
) extends IterableOps.WithFilter[A, IterableCC](`this`, p) {
164164

@@ -175,4 +175,4 @@ object SortedMultiSetOps {
175175

176176
}
177177

178-
object SortedMultiSet extends SortedIterableFactory.Delegate(immutable.SortedMultiSet)
178+
object SortedBag extends SortedIterableFactory.Delegate(immutable.SortedBag)

src/main/scala/scala/collection/SortedMultiDict.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
6969
* @tparam L the type of keys of the returned collection
7070
* @return a new collection resulting from applying the given function
7171
* `f` to each pair of element and its number of occurrences of this
72-
* sorted multiset and collecting the results.
72+
* sorted multidict and collecting the results.
7373
*/
7474
def mapSets[L : Ordering, W](f: ((K, Set[V])) => (L, Set[W])): CC[L, W] = sortedFromSets(new View.Map(sets, f))
7575

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package scala
2+
package collection
3+
package immutable
4+
5+
import scala.collection.mutable.{Builder, ImmutableBuilder}
6+
7+
/**
8+
* An immutable bag
9+
* @tparam A the element type of the collection
10+
*/
11+
trait Bag[A]
12+
extends collection.Bag[A]
13+
with Iterable[A]
14+
with BagOps[A, Bag, Bag[A]] {
15+
16+
override def iterableFactory: IterableFactory[Bag] = Bag
17+
override protected def fromSpecific(coll: IterableOnce[A]): Bag[A] = iterableFactory.from(coll)
18+
override protected def newSpecificBuilder: mutable.Builder[A, Bag[A]] = iterableFactory.newBuilder
19+
override def empty: Bag[A] = iterableFactory.empty
20+
21+
}
22+
23+
trait BagOps[A, +CC[X] <: Bag[X], +C <: Bag[A]] extends collection.BagOps[A, CC, C] {
24+
/**
25+
* @return an immutable bag containing all the elements of this bag
26+
* and one more occurrence of `elem`
27+
* @param elem the element to add
28+
*/
29+
def incl(elem: A): C
30+
31+
/** Alias for `incl` */
32+
@`inline` final def + (elem: A): C = incl(elem)
33+
34+
/**
35+
* @return an immutable bag containing all the elements of this bag
36+
* and one occurrence less of `elem`
37+
*
38+
* @param elem the element to remove
39+
*/
40+
def excl(elem: A): C
41+
42+
/** Alias for `excl` */
43+
@`inline` final def - (elem: A): C = excl(elem)
44+
}
45+
46+
class BagImpl[A] private[immutable](elems: Map[A, Int]) extends Bag[A] {
47+
48+
def occurrences: Map[A, Int] = elems
49+
50+
override def iterableFactory: IterableFactory[Bag] = Bag
51+
52+
/**
53+
* @return an immutable bag containing all the elements of this bag
54+
* and one more occurrence of `elem`
55+
* @param elem the element to add
56+
*/
57+
def incl(elem: A): Bag[A] =
58+
new BagImpl(elems.updatedWith(elem) {
59+
case None => Some(1)
60+
case Some(n) => Some(n + 1)
61+
})
62+
63+
/**
64+
* @return an immutable bag containing all the elements of this bag
65+
* and one occurrence less of `elem`
66+
*
67+
* @param elem the element to remove
68+
*/
69+
def excl(elem: A): Bag[A] =
70+
new BagImpl(elems.updatedWith(elem) {
71+
case Some(n) => if (n > 1) Some(n - 1) else None
72+
case None => None
73+
})
74+
75+
}
76+
77+
object Bag extends IterableFactory[Bag] {
78+
79+
def from[A](source: IterableOnce[A]): Bag[A] =
80+
source match {
81+
case ms: Bag[A] => ms
82+
case _ => (newBuilder[A] ++= source).result()
83+
}
84+
85+
def empty[A] = new BagImpl[A](Map.empty)
86+
87+
def newBuilder[A]: Builder[A, Bag[A]] =
88+
new ImmutableBuilder[A, Bag[A]](empty[A]) {
89+
def addOne(elem: A): this.type = { elems = elems + elem; this }
90+
}
91+
92+
}

src/main/scala/scala/collection/immutable/MultiDict.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ object MultiDict extends MapFactory[MultiDict] {
7373
case _ => (newBuilder[K, V] ++= source).result()
7474
}
7575

76-
def newBuilder[K, V]: Builder[(K, V), MultiDict[K, V]] =
76+
def newBuilder[K, V]: mutable.Builder[(K, V), MultiDict[K, V]] =
7777
new ImmutableBuilder[(K, V), MultiDict[K, V]](empty[K, V]) {
7878
def addOne(elem: (K, V)): this.type = { elems = elems + elem; this }
7979
}

0 commit comments

Comments
 (0)