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
Merged
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
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