Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Add MapView and SeqView #436

Merged
merged 10 commits into from
Feb 21, 2018
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
* @tparam W new type of values
*/
def map[L, W](f: ((K, V)) => (L, W)): CC[L, W] =
multiMapFromIterable(View.Map(toIterable, f))
multiMapFromIterable(new View.Map(toIterable, f))

/**
* @return a multidict that contains all the entries of `this` multidict,
Expand All @@ -112,7 +112,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
* @tparam W new type of values
*/
def flatMap[L, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] =
multiMapFromIterable(View.FlatMap(toIterable, f))
multiMapFromIterable(new View.FlatMap(toIterable, f))

/**
* @return a multidict that contains all the entries of `this` multidict
Expand All @@ -125,19 +125,19 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
*/
def collect[L, W](pf: PartialFunction[(K, V), (L, W)]): CC[L, W] =
flatMap(kv =>
if (pf.isDefinedAt(kv)) View.Single(pf(kv))
if (pf.isDefinedAt(kv)) new View.Single(pf(kv))
else View.Empty
)

/** Concatenate the entries given in `that` iterable to `this` multidict */
def concat(that: Iterable[(K, V)]): C =
fromSpecificIterable(View.Concat(toIterable, that))
fromSpecificIterable(new View.Concat(toIterable, that))

override def withFilter(p: ((K, V)) => Boolean): MultiMapWithFilter = new MultiMapWithFilter(p)

class MultiMapWithFilter(p: ((K, V)) => Boolean) extends WithFilter(p) {
def map[L, W](f: ((K, V)) => (L, W)): CC[L, W] = multiMapFromIterable(View.Map(filtered, f))
def flatMap[L, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = multiMapFromIterable(View.FlatMap(filtered, f))
def map[L, W](f: ((K, V)) => (L, W)): CC[L, W] = multiMapFromIterable(new View.Map(filtered, f))
def flatMap[L, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = multiMapFromIterable(new View.FlatMap(filtered, f))
override def withFilter(q: ((K, V)) => Boolean): MultiMapWithFilter = new MultiMapWithFilter(kv => p(kv) && q(kv))
}

Expand All @@ -157,7 +157,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
* @tparam W the type of values of the returned multidict
*/
def mapSets[L, W](f: ((K, Set[V])) => (L, Set[W])): CC[L, W] =
fromSets(View.Map(sets, f))
fromSets(new View.Map(sets, f))

/**
* @return a multidict that contains all the entries of `this` multidict,
Expand All @@ -170,7 +170,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
*/
def collectSets[L, W](pf: PartialFunction[(K, Set[V]), (L, Set[W])]): CC[L, W] =
flatMapSets(kvs =>
if (pf.isDefinedAt(kvs)) View.Single(pf(kvs))
if (pf.isDefinedAt(kvs)) new View.Single(pf(kvs))
else View.Empty
)

Expand All @@ -183,7 +183,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
* @tparam W the type of values of the returned multidict
*/
def flatMapSets[L, W](f: ((K, Set[V])) => IterableOnce[(L, Set[W])]): CC[L, W] =
fromSets(View.FlatMap(sets, f))
fromSets(new View.FlatMap(sets, f))

/**
* @return a new multidict concatenating the values of this multidict
Expand All @@ -192,14 +192,14 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]]
* @param that the collection of values to add to this multidict
*/
def concatSets(that: Iterable[(K, Set[V])]): C =
fromSpecificSets(View.Concat(sets, that))
fromSpecificSets(new View.Concat(sets, that))

/**
* @return a multidict that contains all the entries of this multidict
* that satisfy the predicate `p`
*/
def filterSets(p: ((K, Set[V])) => Boolean): C =
fromSpecificSets(View.Filter(sets, p, isFlipped = false))
fromSpecificSets(new View.Filter(sets, p, isFlipped = false))

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,19 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
extends IterableOps[A, CC, C] {

protected[this] def fromSpecificOccurrences(it: Iterable[(A, Int)]): C =
fromSpecificIterable(it.view.flatMap { case (e, n) => View.Fill(n)(e) })
fromSpecificIterable(it.view.flatMap { case (e, n) => new View.Fill(n)(e) })

protected[this] def fromOccurrences[E](it: Iterable[(E, Int)]): CC[E] =
// Note new MultiSet(it.to(Map)) would be more efficient but would also loose duplicates
fromIterable(it.view.flatMap { case (e, n) => View.Fill(n)(e) })
fromIterable(it.view.flatMap { case (e, n) => new View.Fill(n)(e) })

/**
* @return All the elements contained in this multiset and their number of occurrences
*/
def occurrences: Map[A, Int]

def iterator(): Iterator[A] =
occurrences.iterator().flatMap { case (elem, n) => View.Fill(n)(elem) }
occurrences.iterator().flatMap { case (elem, n) => new View.Fill(n)(elem) }

/**
* @return The number of occurrences of `elem` in this multiset
Expand All @@ -68,7 +68,7 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* @param that the collection of elements to add to this multiset
*/
def concat(that: Iterable[A]): C =
fromSpecificIterable(View.Concat(toIterable, that))
fromSpecificIterable(new View.Concat(toIterable, that))

/**
* @return a new multiset summing the occurrences of this multiset
Expand All @@ -77,7 +77,7 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* @param that the collection of occurrences to add to this multiset
*/
def concatOccurrences(that: Iterable[(A, Int)]): C =
fromSpecificOccurrences(View.Concat(occurrences, that))
fromSpecificOccurrences(new View.Concat(occurrences, that))

/**
* @return a new multiset resulting from applying the given function `f`
Expand All @@ -87,11 +87,11 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* @tparam B the element type of the returned collection
*/
def mapOccurrences[B](f: ((A, Int)) => (B, Int)): CC[B] =
fromOccurrences(View.Map(occurrences, f))
fromOccurrences(new View.Map(occurrences, f))

def collectOccurrences[B](pf: PartialFunction[(A, Int), (B, Int)]): CC[B] =
flatMapOccurrences(kvs =>
if (pf.isDefinedAt(kvs)) View.Single(pf(kvs))
if (pf.isDefinedAt(kvs)) new View.Single(pf(kvs))
else View.Empty
)

Expand All @@ -103,14 +103,14 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* @tparam B the element type of the returned collection
*/
def flatMapOccurrences[B](f: ((A, Int)) => IterableOnce[(B, Int)]): CC[B] =
fromOccurrences(View.FlatMap(occurrences, f))
fromOccurrences(new View.FlatMap(occurrences, f))

/**
* @return a new multiset containing only the occurrences of elements
* of this multiset that satisfy the given predicate `p`
*/
def filterOccurrences(p: ((A, Int)) => Boolean): C =
fromSpecificOccurrences(View.Filter(occurrences, p, isFlipped = false))
fromSpecificOccurrences(new View.Filter(occurrences, p, isFlipped = false))

// TODO Add more multiset operations like union and intersection

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
override def withFilter(p: ((K, V)) => Boolean): SortedMultiMapWithFilter = new SortedMultiMapWithFilter(p)

class SortedMultiMapWithFilter(p: ((K, V)) => Boolean) extends MultiMapWithFilter(p) {
def map[L : Ordering, W](f: ((K, V)) => (L, W)): CC[L, W] = sortedFromIterable(View.Map(filtered, f))
def flatMap[L : Ordering, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = sortedFromIterable(View.FlatMap(filtered, f))
def map[L : Ordering, W](f: ((K, V)) => (L, W)): CC[L, W] = sortedFromIterable(new View.Map(filtered, f))
def flatMap[L : Ordering, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = sortedFromIterable(new View.FlatMap(filtered, f))
override def withFilter(q: ((K, V)) => Boolean): SortedMultiMapWithFilter = new SortedMultiMapWithFilter(kv => p(kv) && q(kv))
}

Expand All @@ -67,7 +67,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
* @tparam L new type of keys
* @tparam W new type of values
*/
def map[L : Ordering, W](f: ((K, V)) => (L, W)): CC[L, W] = sortedFromIterable(View.Map(toIterable, f))
def map[L : Ordering, W](f: ((K, V)) => (L, W)): CC[L, W] = sortedFromIterable(new View.Map(toIterable, f))

/**
* Builds a new sorted multidict by applying a function to all groups of elements
Expand All @@ -78,7 +78,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
* `f` to each pair of element and its number of occurrences of this
* sorted multiset and collecting the results.
*/
def mapSets[L : Ordering, W](f: ((K, Set[V])) => (L, Set[W])): CC[L, W] = sortedFromSets(View.Map(sets, f))
def mapSets[L : Ordering, W](f: ((K, Set[V])) => (L, Set[W])): CC[L, W] = sortedFromSets(new View.Map(sets, f))

/**
* @return a sorted multidict that contains all the entries of `this` sorted multidict,
Expand All @@ -88,7 +88,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
* @tparam L new type of keys
* @tparam W new type of values
*/
def flatMap[L : Ordering, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = sortedFromIterable(View.FlatMap(toIterable, f))
def flatMap[L : Ordering, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = sortedFromIterable(new View.FlatMap(toIterable, f))

/**
* @return a new sorted multidict resulting from applying the given function `f`
Expand All @@ -98,7 +98,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
* @tparam L the new type of keys
* @tparam W the type of values of the returned sorted multidict
*/
def flatMapSets[L : Ordering, W](f: ((K, Set[V])) => IterableOnce[(L, Set[W])]): CC[L, W] = sortedFromSets(View.FlatMap(sets, f))
def flatMapSets[L : Ordering, W](f: ((K, Set[V])) => IterableOnce[(L, Set[W])]): CC[L, W] = sortedFromSets(new View.FlatMap(sets, f))

/**
* @return a sorted multidict that contains all the entries of `this` sorted multidict
Expand All @@ -110,7 +110,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
* @tparam W new type of values
*/
def collect[L : Ordering, W](pf: PartialFunction[(K, V), (L, W)]): CC[L, W] = flatMap(kv =>
if (pf.isDefinedAt(kv)) View.Single(pf(kv))
if (pf.isDefinedAt(kv)) new View.Single(pf(kv))
else View.Empty
)

Expand All @@ -124,7 +124,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K,
* @tparam W the new type of values
*/
def collectSets[L : Ordering, W](pf: PartialFunction[(K, Set[V]), (L, Set[W])]): CC[L, W] = flatMapSets(kv =>
if (pf.isDefinedAt(kv)) View.Single(pf(kv))
if (pf.isDefinedAt(kv)) new View.Single(pf(kv))
else View.Empty
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]

protected[this] def sortedFromIterable[B : Ordering](it: Iterable[B]): SortedIterableCC[B]
protected[this] def sortedFromOccurrences[B : Ordering](it: Iterable[(B, Int)]): CC[B] =
sortedFromIterable(it.view.flatMap { case (b, n) => View.Fill(n)(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]
Expand All @@ -46,7 +46,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* @param start The lower-bound (inclusive) of the iterator
*/
def iteratorFrom(start: A): Iterator[A] =
occurrences.iteratorFrom(start).flatMap { case (elem, n) => View.Fill(n)(elem) }
occurrences.iteratorFrom(start).flatMap { case (elem, n) => new View.Fill(n)(elem) }

def firstKey: A = occurrences.firstKey
def lastKey: A = occurrences.lastKey
Expand All @@ -70,9 +70,9 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
*/
class SortedWithFilter(p: A => Boolean) extends WithFilter(p) {

def map[B : Ordering](f: A => B): CC[B] = sortedIterableFactory.from(View.Map(filtered, f))
def map[B : Ordering](f: A => B): CC[B] = sortedIterableFactory.from(new View.Map(filtered, f))

def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedIterableFactory.from(View.FlatMap(filtered, f))
def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedIterableFactory.from(new View.FlatMap(filtered, f))

override def withFilter(q: A => Boolean): SortedWithFilter = new SortedWithFilter(a => p(a) && q(a))

Expand All @@ -85,7 +85,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* @return a new collection resulting from applying the given function
* `f` to each element of this sorted multiset and collecting the results.
*/
def map[B : Ordering](f: A => B): CC[B] = sortedFromIterable(View.Map(toIterable, f))
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
Expand All @@ -98,7 +98,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* sorted multiset and collecting the results.
*/
def mapOccurrences[B : Ordering](f: ((A, Int)) => (B, Int)): CC[B] =
sortedFromOccurrences(View.Map(occurrences, f))
sortedFromOccurrences(new View.Map(occurrences, f))

/**
* Builds a new collection by applying a function to all elements of this sorted
Expand All @@ -109,7 +109,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* @return a new collection resulting from applying the given function `f` to
* each element of this sorted multiset and concatenating the results.
*/
def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedFromIterable(View.FlatMap(toIterable, f))
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
Expand All @@ -123,7 +123,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* multiset and concatenating the results.
*/
def flatMapOccurrences[B : Ordering](f: ((A, Int)) => IterableOnce[(B, Int)]): CC[B] =
sortedFromOccurrences(View.FlatMap(occurrences, f))
sortedFromOccurrences(new View.FlatMap(occurrences, f))

/**
* Returns a sorted multiset formed from this sorted multiset and another iterable
Expand All @@ -136,7 +136,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* 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
sortedFromIterable(View.Zip(toIterable, that))
sortedFromIterable(new View.Zip(toIterable, that))

/**
* @return a new collection resulting from applying the given partial
Expand All @@ -146,7 +146,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* @tparam B the element type of the returned collection
*/
def collect[B : Ordering](pf: PartialFunction[A, B]): CC[B] = flatMap(a =>
if (pf.isDefinedAt(a)) View.Single(pf(a))
if (pf.isDefinedAt(a)) new View.Single(pf(a))
else View.Empty
)

Expand All @@ -158,14 +158,14 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]]
* @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)) View.Single(pf(a))
if (pf.isDefinedAt(a)) new View.Single(pf(a))
else View.Empty
)

// --- Override return type of methods that returned an unsorted MultiSet

override def zipWithIndex: CC[(A, Int)] =
sortedFromIterable(View.ZipWithIndex(toIterable))
sortedFromIterable(new View.ZipWithIndex(toIterable))

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class SeqDecorator[A, CC[X] <: SeqOps[X, CC, _]](`this`: CC[A]) {
* }}}
*/
def intersperse[B >: A](sep: B): CC[B] =
`this`.iterableFactory.from(View.Intersperse(`this`.toIterable, sep))
`this`.iterableFactory.from(new View.Intersperse(`this`.toIterable, sep))

/** Adds the element `sep` between each element of the sequence,
* prepending `start` and appending `end`.
Expand All @@ -42,6 +42,6 @@ class SeqDecorator[A, CC[X] <: SeqOps[X, CC, _]](`this`: CC[A]) {
* }}}
*/
def intersperse[B >: A, C](start: B, sep: B, end: B): CC[B] =
`this`.iterableFactory.from(View.IntersperseSurround(`this`.toIterable, start, sep, end))
`this`.iterableFactory.from(new View.IntersperseSurround(`this`.toIterable, start, sep, end))

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ package decorators
/** Views used by decorators */
object View {

case class Intersperse[A](underlying: Iterable[A], sep: A) extends View[A] {
class Intersperse[A](underlying: Iterable[A], sep: A) extends View[A] {
def iterator(): Iterator[A] = underlying.iterator().intersperse(sep)

override def knownSize: Int = if (underlying.knownSize > 0) (2 * underlying.knownSize - 1) else underlying.knownSize
}

case class IntersperseSurround[A](underlying: Iterable[A], start: A, sep: A, end: A) extends View[A] {
class IntersperseSurround[A](underlying: Iterable[A], start: A, sep: A, end: A) extends View[A] {
def iterator(): Iterator[A] = underlying.iterator().intersperse(start, sep, end)

override def knownSize: Int =
Expand Down
Loading