izumi.fundamentals.collections.nonempty.NESet.scala Maven / Gradle / Ivy
package izumi.fundamentals.collections.nonempty
// shameless copypaste from Scalactic
import scala.collection.compat.*
import scala.collection.mutable.{ArrayBuffer, Buffer}
import scala.language.implicitConversions
import scala.reflect.ClassTag
// Can't be a LinearSeq[T] because Builder would be able to create an empty one.
/**
* A non-empty Set: an ordered, immutable, non-empty collection of elements with LinearSeq
performance characteristics.
*
*
* The purpose of NESet
is to allow you to express in a type that a Set
is non-empty, thereby eliminating the
* need for (and potential exception from) a run-time check for non-emptiness. For a non-empty sequence with IndexedSeq
* performance, see Vector
.
*
*
* Constructing NESet
s
*
*
* You can construct a NESet
by passing one or more elements to the NESet.apply
factory method:
*
*
*
* scala> NESet(1, 2, 3)
* res0: org.scalactic.anyvals.NESet[Int] = NESet(1, 2, 3)
*
*
*
* Alternatively you can cons elements onto the End
singleton object, similar to making a Set
starting with Nil
:
*
*
*
* scala> 1 :: 2 :: 3 :: Nil
* res0: Set[Int] = Set(1, 2, 3)
*
* scala> 1 :: 2 :: 3 :: End
* res1: org.scalactic.NESet[Int] = NESet(1, 2, 3)
*
*
*
* Note that although Nil
is a Set[Nothing]
, End
is
* not a NESet[Nothing]
, because no empty NESet
exists. (A non-empty Set is a series
* of connected links; if you have no links, you have no non-empty Set.)
*
*
*
* scala> val nil: Set[Nothing] = Nil
* nil: Set[Nothing] = Set()
*
* scala> val nada: NESet[Nothing] = End
* <console>:16: error: type mismatch;
* found : org.scalactic.anyvals.End.type
* required: org.scalactic.anyvals.NESet[Nothing]
* val nada: NESet[Nothing] = End
* ^
*
*
* Working with NESet
s
*
*
* NESet
does not extend Scala's Seq
or Traversable
traits because these require that
* implementations may be empty. For example, if you invoke tail
on a Seq
that contains just one element,
* you'll get an empty Seq
:
*
*
*
* scala> Set(1).tail
* res6: Set[Int] = Set()
*
*
*
* On the other hand, many useful methods exist on Seq
that when invoked on a non-empty Seq
are guaranteed
* to not result in an empty Seq
. For convenience, NESet
defines a method corresponding to every such Seq
* method. Here are some examples:
*
*
*
* NESet(1, 2, 3).map(_ + 1) // Result: NESet(2, 3, 4)
* NESet(1).map(_ + 1) // Result: NESet(2)
* NESet(1, 2, 3).containsSlice(NESet(2, 3)) // Result: true
* NESet(1, 2, 3).containsSlice(NESet(3, 4)) // Result: false
* NESet(-1, -2, 3, 4, 5).minBy(_.abs) // Result: -1
*
*
*
* NESet
does not currently define any methods corresponding to Seq
methods that could result in
* an empty Seq
. However, an implicit converison from NESet
to Set
* is defined in the NESet
companion object that will be applied if you attempt to call one of the missing methods. As a
* result, you can invoke filter
on an NESet
, even though filter
could result
* in an empty sequence—but the result type will be Set
instead of NESet
:
*
*
*
* NESet(1, 2, 3).filter(_ < 10) // Result: Set(1, 2, 3)
* NESet(1, 2, 3).filter(_ > 10) // Result: Set()
*
*
*
* You can use NESet
s in for
expressions. The result will be an NESet
unless
* you use a filter (an if
clause). Because filters are desugared to invocations of filter
, the
* result type will switch to a Set
at that point. Here are some examples:
*
*
*
* scala> import org.scalactic.anyvals._
* import org.scalactic.anyvals._
*
* scala> for (i <- NESet(1, 2, 3)) yield i + 1
* res0: org.scalactic.anyvals.NESet[Int] = NESet(2, 3, 4)
*
* scala> for (i <- NESet(1, 2, 3) if i < 10) yield i + 1
* res1: Set[Int] = Set(2, 3, 4)
*
* scala> for {
* | i <- NESet(1, 2, 3)
* | j <- NESet('a', 'b', 'c')
* | } yield (i, j)
* res3: org.scalactic.anyvals.NESet[(Int, Char)] =
* NESet((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))
*
* scala> for {
* | i <- NESet(1, 2, 3) if i < 10
* | j <- NESet('a', 'b', 'c')
* | } yield (i, j)
* res6: Set[(Int, Char)] =
* Set((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))
*
*
* @tparam T the type of elements contained in this NESet
*/
final class NESet[T] private (val toSet: Set[T]) extends AnyVal {
/**
* Returns a new NESet
containing the elements of this NESet
followed by the elements of the passed NESet
.
* The element type of the resulting NESet
is the most specific superclass encompassing the element types of this and the passed NESet
.
*
* @tparam U the element type of the returned NESet
* @param other the NESet
to append
* @return a new NESet
that contains all the elements of this NESet
followed by all elements of other
.
*/
def ++[U >: T](other: NESet[U]): NESet[U] = new NESet(toSet ++ other.toSet)
/**
* Returns a new NESet
containing the elements of this NESet
followed by the elements of the passed Vector
.
* The element type of the resulting NESet
is the most specific superclass encompassing the element types of this NESet
and the passed Vector
.
*
* @tparam U the element type of the returned NESet
* @param other the Vector
to append
* @return a new NESet
that contains all the elements of this NESet
followed by all elements of other
.
*/
def ++[U >: T](other: Vector[U]): NESet[U] = new NESet(toSet ++ other)
// TODO: Have I added these extra ++, etc. methods to Vector that take a NESet?
/**
* Returns a new NESet
containing the elements of this NESet
followed by the elements of the passed GenTraversableOnce
.
* The element type of the resulting NESet
is the most specific superclass encompassing the element types of this NESet
* and the passed GenTraversableOnce
.
*
* @param other the GenTraversableOnce
to append
* @return a new NESet
that contains all the elements of this NESet
followed by all elements of other
.
*/
def ++(other: IterableOnce[T]): NESet[T] =
if (other.iterator.isEmpty) this else new NESet(toSet ++ other.iterator.to(Set))
/**
* Returns a new NESet
with the given element added.
*
* @param element the element to add to this NESet
* @return a new NESet
consisting of element
and all elements of this NESet
.
*/
def +(element: T): NESet[T] = new NESet(toSet ++ Set(element))
/**
* Appends all elements of this NESet
to a string builder. The written text will consist of a concatenation of the result of invoking toString
* on of every element of this NESet
, without any separator string.
*
* @param sb the string builder to which elements will be appended
* @return the string builder, sb
, to which elements were appended.
*/
def addString(sb: StringBuilder): StringBuilder = toSet.addString(sb)
/**
* Check if an element exists at its index in the NESet
.
*
* @return true
if a element exists in NESet
at index idx
, where false
indicates the element at index idx
does not exist.
*/
def apply(elem: T): Boolean = toSet(elem)
/**
* Appends all elements of this NESet
to a string builder using a separator string. The written text will consist of a concatenation of the
* result of invoking toString
* on of every element of this NESet
, separated by the string sep
.
*
* @param sb the string builder to which elements will be appended
* @param sep the separator string
* @return the string builder, sb
, to which elements were appended.
*/
def addString(sb: StringBuilder, sep: String): StringBuilder = toSet.addString(sb, sep)
/**
* Appends all elements of this NESet
to a string builder using start, end, and separator strings. The written text will consist of a concatenation of
* the string start
; the result of invoking toString
on all elements of this NESet
,
* separated by the string sep
; and the string end
*
* @param sb the string builder to which elements will be appended
* @param start the starting string
* @param sep the separator string
* @param start the ending string
* @return the string builder, sb
, to which elements were appended.
*/
def addString(sb: StringBuilder, start: String, sep: String, end: String): StringBuilder = toSet.addString(sb, start, sep, end)
/**
* Finds the first element of this NESet
for which the given partial function is defined, if any, and applies the partial function to it.
*
* @param pf the partial function
* @return an Option
containing pf
applied to the first element for which it is defined, or None
if
* the partial function was not defined for any element.
*/
def collectFirst[U](pf: PartialFunction[T, U]): Option[U] = toSet.collectFirst(pf)
/**
* Indicates whether this NESet
contains a given value as an element.
*
* @param elem the element to look for
* @return true if this NESet
has an element that is equal (as determined by ==)
to elem
, false otherwise.
*/
infix def contains(elem: T): Boolean = toSet.contains(elem)
/**
* Copies values of this NESet
to an array. Fills the given array arr
with values of this NESet
. Copying
* will stop once either the end of the current NESet
is reached, or the end of the array is reached.
*
* @param arr the array to fill
*/
def copyToArray[U >: T](arr: Array[U]): Unit = {
toSet.copyToArray(arr)
()
}
/**
* Copies values of this NESet
to an array. Fills the given array arr
with values of this NESet
, beginning at
* index start
. Copying will stop once either the end of the current NESet
is reached, or the end of the array is reached.
*
* @param arr the array to fill
* @param start the starting index
*/
def copyToArray[U >: T](arr: Array[U], start: Int): Unit = {
toSet.copyToArray(arr, start)
()
}
/**
* Copies values of this NESet
to an array. Fills the given array arr
with at most len
elements of this NESet
, beginning at
* index start
. Copying will stop once either the end of the current NESet
is reached, the end of the array is reached, or
* len
elements have been copied.
*
* @param arr the array to fill
* @param start the starting index
* @param len the maximum number of elements to copy
*/
def copyToArray[U >: T](arr: Array[U], start: Int, len: Int): Unit = {
toSet.copyToArray(arr, start, len)
()
}
/**
* Copies all elements of this NESet
to a buffer.
*
* @param buf the buffer to which elements are copied
*/
def copyToBuffer[U >: T](buf: Buffer[U]): Unit = {
buf ++= toSet
()
}
/**
* Counts the number of elements in this NESet
that satisfy a predicate.
*
* @param p the predicate used to test elements.
* @return the number of elements satisfying the predicate p
.
*/
def count(p: T => Boolean): Int = toSet.count(p)
/**
* Indicates whether a predicate holds for at least one of the elements of this NESet
.
*
* @param p the predicate used to test elements.
* @return true
if the given predicate p
holds for some of the elements of this NESet
, otherwise false
.
*/
def exists(p: T => Boolean): Boolean = toSet.exists(p)
/**
* Finds the first element of this NESet
that satisfies the given predicate, if any.
*
* @param p the predicate used to test elements
* @return an Some
containing the first element in this NESet
that satisfies p
, or None
if none exists.
*/
def find(p: T => Boolean): Option[T] = toSet.find(p)
/**
* Builds a new NESet
by applying a function to all elements of this NESet
and using the elements of the resulting NESet
s.
*
* @tparam U the element type of the returned NESet
* @param f the function to apply to each element.
* @return a new NESet
containing elements obtained by applying the given function f
to each element of this NESet
and concatenating
* the elements of resulting NESet
s.
*/
def flatMap[U](f: T => NESet[U]): NESet[U] = {
val buf = new ArrayBuffer[U]
for (ele <- toSet)
buf ++= f(ele).toSet
new NESet(buf.toSet)
}
/**
* Converts this NESet
of NESet
s into a NESet
* formed by the elements of the nested NESet
s.
*
*
* @note You cannot use this flatten
method on a NESet
that contains a GenTraversableOnce
s, because
* if all the nested GenTraversableOnce
s were empty, you'd end up with an empty NESet
.
*
*
* @tparm B the type of the elements of each nested NESet
* @return a new NESet
resulting from concatenating all nested NESet
s.
*/
def flatten[B](implicit ev: T <:< NESet[B]): NESet[B] = flatMap(ev)
/**
* Folds the elements of this NESet
using the specified associative binary operator.
*
*
* The order in which operations are performed on elements is unspecified and may be nondeterministic.
*
*
* @tparam U a type parameter for the binary operator, a supertype of T.
* @param z a neutral element for the fold operation; may be added to the result an arbitrary number of
* times, and must not change the result (e.g., Nil
for Set concatenation,
* 0 for addition, or 1 for multiplication.)
* @param op a binary operator that must be associative
* @return the result of applying fold operator op
between all the elements and z
*/
def fold[U >: T](z: U)(op: (U, U) => U): U = toSet.fold(z)(op)
/**
* Applies a binary operator to a start value and all elements of this NESet
, going left to right.
*
* @tparam B the result type of the binary operator.
* @param z the start value.
* @param op the binary operator.
* @return the result of inserting op
between consecutive elements of this NESet
, going left to right, with the start value,
* z
, on the left:
*
*
* op(...op(op(z, x_1), x_2), ..., x_n)
*
*
*
* where x1, ..., xn are the elements of this NESet
.
*
*/
def foldLeft[B](z: B)(op: (B, T) => B): B = toSet.foldLeft(z)(op)
/**
* Applies a binary operator to all elements of this NESet
and a start value, going right to left.
*
* @tparam B the result of the binary operator
* @param z the start value
* @param op the binary operator
* @return the result of inserting op
between consecutive elements of this NESet
, going right to left, with the start value,
* z
, on the right:
*
*
* op(x_1, op(x_2, ... op(x_n, z)...))
*
*
*
* where x1, ..., xn are the elements of this NESet
.
*
*/
def foldRight[B](z: B)(op: (T, B) => B): B = toSet.foldRight(z)(op)
/**
* Indicates whether a predicate holds for all elements of this NESet
.
*
* @param p the predicate used to test elements.
* @return true
if the given predicate p
holds for all elements of this NESet
, otherwise false
.
*/
def forall(p: T => Boolean): Boolean = toSet.forall(p)
/**
* Applies a function f
to all elements of this NESet
.
*
* @param f the function that is applied for its side-effect to every element. The result of function f
is discarded.
*/
def foreach(f: T => Unit): Unit = toSet.foreach(f)
/**
* Partitions this NESet
into a map of NESet
s according to some discriminator function.
*
* @tparam K the type of keys returned by the discriminator function.
* @param f the discriminator function.
* @return A map from keys to NESet
s such that the following invariant holds:
*
*
* (NESet.toSet partition f)(k) = xs filter (x => f(x) == k)
*
*
*
* That is, every key k
is bound to a NESet
of those elements x
for which f(x)
equals k
.
*
*/
def groupBy[K](f: T => K): Map[K, NESet[T]] = {
val mapKToSet = toSet.groupBy(f)
mapKToSet.view.mapValues {
Set => new NESet(Set)
}.toMap
}
/**
* Partitions elements into fixed size NESet
s.
*
* @param size the number of elements per group
* @return An iterator producing NESet
s of size size
, except the last will be truncated if the elements don't divide evenly.
*/
def grouped(size: Int): Iterator[NESet[T]] = {
val itOfSet = toSet.grouped(size)
itOfSet.map {
Set => new NESet(Set)
}
}
/**
* Returns true
to indicate this NESet
has a definite size, since all NESet
s are strict collections.
*/
def hasDefiniteSize: Boolean = true
// override def hashCode: Int = toSet.hashCode
/**
* Selects the first element of this NESet
.
*
* @return the first element of this NESet
.
*/
def head: T = toSet.head
def tail: Set[T] = toSet.tail
/**
* Returns false
to indicate this NESet
, like all NESet
s, is non-empty.
*
* @return false
*/
def isEmpty: Boolean = false
/**
* Returns true
to indicate this NESet
, like all NESet
s, can be traversed repeatedly.
*
* @return true
*/
def isTraversableAgain: Boolean = true
/**
* Creates and returns a new iterator over all elements contained in this NESet
.
*
* @return the new iterator
*/
def iterator: Iterator[T] = toSet.iterator
/**
* Selects the last element of this NESet
.
*
* @return the last element of this NESet
.
*/
def last: T = toSet.last
/**
* Builds a new NESet
by applying a function to all elements of this NESet
.
*
* @tparam U the element type of the returned NESet
.
* @param f the function to apply to each element.
* @return a new NESet
resulting from applying the given function f
to each element of this NESet
and collecting the results.
*/
def map[U](f: T => U): NESet[U] =
new NESet(toSet.map(f))
/**
* Finds the largest element.
*
* @return the largest element of this NESet
.
*/
def max[U >: T](implicit cmp: Ordering[U]): T = toSet.max(cmp)
/**
* Finds the largest result after applying the given function to every element.
*
* @return the largest result of applying the given function to every element of this NESet
.
*/
def maxBy[U](f: T => U)(implicit cmp: Ordering[U]): T = toSet.maxBy(f)(cmp)
/**
* Finds the smallest element.
*
* @return the smallest element of this NESet
.
*/
def min[U >: T](implicit cmp: Ordering[U]): T = toSet.min(cmp)
/**
* Finds the smallest result after applying the given function to every element.
*
* @return the smallest result of applying the given function to every element of this NESet
.
*/
def minBy[U](f: T => U)(implicit cmp: Ordering[U]): T = toSet.minBy(f)(cmp)
/**
* Displays all elements of this NESet
in a string.
*
* @return a string representation of this NESet
. In the resulting string, the result of invoking toString
on all elements of this
* NESet
follow each other without any separator string.
*/
def mkString: String = toSet.mkString
/**
* Displays all elements of this NESet
in a string using a separator string.
*
* @param sep the separator string
* @return a string representation of this NESet
. In the resulting string, the result of invoking toString
on all elements of this
* NESet
are separated by the string sep
.
*/
def mkString(sep: String): String = toSet.mkString(sep)
/**
* Displays all elements of this NESet
in a string using start, end, and separator strings.
*
* @param start the starting string.
* @param sep the separator string.
* @param end the ending string.
* @return a string representation of this NESet
. The resulting string begins with the string start
and ends with the string
* end
. Inside, In the resulting string, the result of invoking toString
on all elements of this NESet
are
* separated by the string sep
.
*/
def mkString(start: String, sep: String, end: String): String = toSet.mkString(start, sep, end)
/**
* Returns true
to indicate this NESet
, like all NESet
s, is non-empty.
*
* @return true
*/
def nonEmpty: Boolean = true
/**
* The result of multiplying all the elements of this NESet
.
*
*
* This method can be invoked for any NESet[T]
for which an implicit Numeric[T]
exists.
*
*
* @return the product of all elements
*/
def product[U >: T](implicit num: Numeric[U]): U = toSet.product(num)
/**
* Reduces the elements of this NESet
using the specified associative binary operator.
*
*
* The order in which operations are performed on elements is unspecified and may be nondeterministic.
*
*
* @tparam U a type parameter for the binary operator, a supertype of T.
* @param op a binary operator that must be associative.
* @return the result of applying reduce operator op
between all the elements of this NESet
.
*/
def reduce[U >: T](op: (U, U) => U): U = toSet.reduce(op)
/**
* Applies a binary operator to all elements of this NESet
, going left to right.
*
* @tparam U the result type of the binary operator.
* @param op the binary operator.
* @return the result of inserting op
between consecutive elements of this NESet
, going left to right:
*
*
* op(...op(op(x_1, x_2), x_3), ..., x_n)
*
*
*
* where x1, ..., xn are the elements of this NESet
.
*
*/
def reduceLeft[U >: T](op: (U, T) => U): U = toSet.reduceLeft(op)
/**
* Applies a binary operator to all elements of this NESet
, going left to right, returning the result in a Some
.
*
* @tparam U the result type of the binary operator.
* @param op the binary operator.
* @return a Some
containing the result of reduceLeft(op)
*
*/
def reduceLeftOption[U >: T](op: (U, T) => U): Option[U] = toSet.reduceLeftOption(op)
def reduceOption[U >: T](op: (U, U) => U): Option[U] = toSet.reduceOption(op)
/**
* Applies a binary operator to all elements of this NESet
, going right to left.
*
* @tparam U the result of the binary operator
* @param op the binary operator
* @return the result of inserting op
between consecutive elements of this NESet
, going right to left:
*
*
* op(x_1, op(x_2, ... op(x_{n-1}, x_n)...))
*
*
*
* where x1, ..., xn are the elements of this NESet
.
*
*/
def reduceRight[U >: T](op: (T, U) => U): U = toSet.reduceRight(op)
/**
* Applies a binary operator to all elements of this NESet
, going right to left, returning the result in a Some
.
*
* @tparam U the result of the binary operator
* @param op the binary operator
* @return a Some
containing the result of reduceRight(op)
*/
def reduceRightOption[U >: T](op: (T, U) => U): Option[U] = toSet.reduceRightOption(op)
/**
* Checks if the given Iterable
contains the same elements in the same order as this NESet
.
*
* @param that the Iterable
with which to compare
* @return true
, if both this NESet
and the given Iterable
contain the same elements
* in the same order, false
otherwise.
*/
def sameElements[U >: T](that: Iterable[U]): Boolean = toSet == that.toSet
/**
* Checks if the given Vector
contains the same elements in the same order as this NESet
.
*
* @param that the Vector
with which to compare
* @return true
, if both this and the given Vector
contain the same elements
* in the same order, false
otherwise.
*/
def sameElements[U >: T](that: Vector[U]): Boolean = toSet == that.toSet
/**
* Checks if the given NESet
contains the same elements in the same order as this NESet
.
*
* @param that the NESet
with which to compare
* @return true
, if both this and the given NESet
contain the same elements
* in the same order, false
otherwise.
*/
def sameElements[U >: T](that: NESet[U]): Boolean = toSet == that.toSet
/**
* Computes a prefix scan of the elements of this NESet
.
*
*
* @note The neutral element z may be applied more than once.
*
*
*
* Here are some examples:
*
*
*
* NESet(1, 2, 3).scan(0)(_ + _) == NESet(0, 1, 3, 6)
* NESet(1, 2, 3).scan("z")(_ + _.toString) == NESet("z", "z1", "z12", "z123")
*
*
* @tparam U a type parameter for the binary operator, a supertype of T, and the type of the resulting NESet
.
* @param z a neutral element for the scan operation; may be added to the result an arbitrary number of
* times, and must not change the result (e.g., Nil
for Set concatenation,
* 0 for addition, or 1 for multiplication.)
* @param op a binary operator that must be associative
* @return a new NESet
containing the prefix scan of the elements in this NESet
*/
def scan[U >: T](z: U)(op: (U, U) => U): NESet[U] = new NESet(toSet.scan(z)(op))
/**
* Produces a NESet
containing cumulative results of applying the operator going left to right.
*
*
* Here are some examples:
*
*
*
* NESet(1, 2, 3).scanLeft(0)(_ + _) == NESet(0, 1, 3, 6)
* NESet(1, 2, 3).scanLeft("z")(_ + _) == NESet("z", "z1", "z12", "z123")
*
*
* @tparam B the result type of the binary operator and type of the resulting NESet
* @param z the start value.
* @param op the binary operator.
* @return a new NESet
containing the intermediate results of inserting op
between consecutive elements of this NESet
,
* going left to right, with the start value, z
, on the left.
*/
def scanLeft[B](z: B)(op: (B, T) => B): NESet[B] = new NESet(toSet.scanLeft(z)(op))
/**
* Produces a NESet
containing cumulative results of applying the operator going right to left.
*
*
* Here are some examples:
*
*
*
* NESet(1, 2, 3).scanRight(0)(_ + _) == NESet(6, 5, 3, 0)
* NESet(1, 2, 3).scanRight("z")(_ + _) == NESet("123z", "23z", "3z", "z")
*
*
* @tparam B the result of the binary operator and type of the resulting NESet
* @param z the start value
* @param op the binary operator
* @return a new NESet
containing the intermediate results of inserting op
between consecutive elements of this NESet
,
* going right to left, with the start value, z
, on the right.
*/
def scanRight[B](z: B)(op: (T, B) => B): NESet[B] = new NESet(toSet.scanRight(z)(op))
/**
* Groups elements in fixed size blocks by passing a “sliding window” over them (as opposed to partitioning them, as is done in grouped.)
*
* @param size the number of elements per group
* @return an iterator producing NESet
s of size size
, except the last and the only element will be truncated
* if there are fewer elements than size
.
*/
def sliding(size: Int): Iterator[NESet[T]] = toSet.sliding(size).map(new NESet(_))
/**
* Groups elements in fixed size blocks by passing a “sliding window” over them (as opposed to partitioning them, as is done in grouped.),
* moving the sliding window by a given step
each time.
*
* @param size the number of elements per group
* @param step the distance between the first elements of successive groups
* @return an iterator producing NESet
s of size size
, except the last and the only element will be truncated
* if there are fewer elements than size
.
*/
def sliding(size: Int, step: Int): Iterator[NESet[T]] = toSet.sliding(size, step).map(new NESet(_))
/**
* The size of this NESet
.
*
*
* @note length
and size
yield the same result, which will be >
= 1.
*
*
* @return the number of elements in this NESet
.
*/
def size: Int = toSet.size
/**
* Returns "NESet"
, the prefix of this object's toString
representation.
*
* @return the string "NESet"
*/
def stringPrefix: String = "NESet"
infix def subsetOf(that: Set[T]): Boolean = toSet.subsetOf(that)
/**
* The result of summing all the elements of this NESet
.
*
*
* This method can be invoked for any NESet[T]
for which an implicit Numeric[T]
exists.
*
*
* @return the sum of all elements
*/
def sum[U >: T](implicit num: Numeric[U]): U = toSet.sum(num)
/**
* Converts this NESet
into a collection of type Col
by copying all elements.
*
* @tparam C1 the collection type to build.
* @return a new collection containing all elements of this NESet
.
*/
def to[C1](factory: Factory[T, C1]): C1 = factory.fromSpecific(iterator)
/**
* Converts this NESet
to an array.
*
* @return an array containing all elements of this NESet
. A ClassTag
must be available for the element type of this NESet
.
*/
def toArray[U >: T](implicit classTag: ClassTag[U]): Array[U] = toSet.toArray
/**
* Converts this NESet
to a Vector
.
*
* @return a Vector
containing all elements of this NESet
.
*/
def toVector: Vector[T] = toSet.toVector
/**
* Converts this NESet
to a mutable buffer.
*
* @return a buffer containing all elements of this NESet
.
*/
def toBuffer[U >: T]: Buffer[U] = toSet.toBuffer
/**
* Converts this NESet
to an immutable IndexedSeq
.
*
* @return an immutable IndexedSeq
containing all elements of this NESet
.
*/
def toIndexedSeq: scala.collection.immutable.IndexedSeq[T] = toSet.toVector
/**
* Converts this NESet
to an iterable collection.
*
* @return an Iterable
containing all elements of this NESet
.
*/
def toIterable: Iterable[T] = toSet
/**
* Returns an Iterator
over the elements in this NESet
.
*
* @return an Iterator
containing all elements of this NESet
.
*/
def toIterator: Iterator[T] = toSet.iterator
/**
* Converts this NESet
to a Set.
*
* @return a Set containing all elements of this NESet
.
*/
// def toSet: Set[T] = toSet
/**
* Converts this NESet
to a map.
*
*
* This method is unavailable unless the elements are members of Tuple2
, each ((K, V))
becoming a key-value pair
* in the map. Duplicate keys will be overwritten by later keys.
*
*
* @return a map of type immutable.Map[K, V]
containing all key/value pairs of type (K, V)
of this NESet
.
*/
def toMap[K, V](implicit ev: T <:< (K, V)): Map[K, V] = toSet.toMap
/**
* Converts this NESet
to an immutable IndexedSeq
.
*
* @return an immutable IndexedSeq
containing all elements of this NESet
.
*/
def toSeq: Seq[T] = toSet.toSeq
/**
* Converts this NESet
to a set.
*
* @return a set containing all elements of this NESet
.
*/
def toList: scala.collection.immutable.List[T] = toSet.toList
/**
* Returns a string representation of this NESet
.
*
* @return the string "NESet"
followed by the result of invoking toString
on
* this NESet
's elements, surrounded by parentheses.
*/
override def toString: String = "NESet(" + toSet.mkString(", ") + ")"
def transpose[U](implicit ev: T <:< NESet[U]): NESet[NESet[U]] = {
val asSets = toSet.map(ev)
val Set = asSets.map(_.toSet).transpose
new NESet(Set.map(new NESet(_)))
}
/**
* Produces a new NESet
that contains all elements of this NESet
and also all elements of a given Vector
.
*
*
* NESetX
union
everyY
is equivalent to NESetX
++
everyY
.
*
*
*
* Another way to express this is that NESetX
union
everyY
computes the order-presevring multi-set union
* of NESetX
and everyY
. This union
method is hence a counter-part of diff
and intersect
that
* also work on multi-sets.
*
*
* @param that the Vector
to add.
* @return a new NESet
that contains all elements of this NESet
followed by all elements of that
Vector
.
*/
infix def union(that: Vector[T]): NESet[T] = new NESet(toSet union that.toSet)
/**
* Produces a new NESet
that contains all elements of this NESet
and also all elements of a given NESet
.
*
*
* NESetX
union
NESetY
is equivalent to NESetX
++
NESetY
.
*
*
*
* Another way to express this is that NESetX
union
NESetY
computes the order-presevring multi-set union
* of NESetX
and NESetY
. This union
method is hence a counter-part of diff
and intersect
that
* also work on multi-sets.
*
*
* @param that the NESet
to add.
* @return a new NESet
that contains all elements of this NESet
followed by all elements of that
.
*/
infix def union(that: NESet[T]): NESet[T] = new NESet(toSet union that.toSet)
/**
* Produces a new NESet
that contains all elements of this NESet
and also all elements of a given GenSeq
.
*
*
* NESetX
union
ys
is equivalent to NESetX
++
ys
.
*
*
*
* Another way to express this is that NESetX
union
ys
computes the order-presevring multi-set union
* of NESetX
and ys
. This union
method is hence a counter-part of diff
and intersect
that
* also work on multi-sets.
*
*
* @param that the Set
to add.
* @return a new NESet
that contains all elements of this NESet
followed by all elements of that
GenSeq
.
*/
infix def union(that: Set[T])(implicit dummyImplicit: DummyImplicit): NESet[T] = new NESet(toSet.union(that))
/**
* Converts this NESet
of pairs into two NESet
s of the first and second half of each pair.
*
* @tparam L the type of the first half of the element pairs
* @tparam R the type of the second half of the element pairs
* @param asPair an implicit conversion that asserts that the element type of this NESet
is a pair.
* @return a pair of NESet
s, containing the first and second half, respectively, of each element pair of this NESet
.
*/
def unzip[L, R](implicit asPair: T => (L, R)): (NESet[L], NESet[R]) = {
val unzipped = toSet.unzip
(new NESet(unzipped._1), new NESet(unzipped._2))
}
/**
* Converts this NESet
of triples into three NESet
s of the first, second, and and third element of each triple.
*
* @tparam L the type of the first member of the element triples
* @tparam M the type of the second member of the element triples
* @tparam R the type of the third member of the element triples
* @param asTriple an implicit conversion that asserts that the element type of this NESet
is a triple.
* @return a triple of NESet
s, containing the first, second, and third member, respectively, of each element triple of this NESet
.
*/
def unzip3[L, M, R](implicit asTriple: T => (L, M, R)): (NESet[L], NESet[M], NESet[R]) = {
val unzipped = toSet.unzip3
(new NESet(unzipped._1), new NESet(unzipped._2), new NESet(unzipped._3))
}
/**
* Returns a NESet
formed from this NESet
and an iterable collection by combining corresponding
* elements in pairs. If one of the two collections is shorter than the other, placeholder elements will be used to extend the
* shorter collection to the length of the longer.
*
* @tparm O the type of the second half of the returned pairs
* @tparm U the type of the first half of the returned pairs
* @param other the Iterable
providing the second half of each result pair
* @param thisElem the element to be used to fill up the result if this NESet
is shorter than that
Iterable
.
* @param otherElem the element to be used to fill up the result if that
Iterable
is shorter than this NESet
.
* @return a new NESet
containing pairs consisting of corresponding elements of this NESet
and that
. The
* length of the returned collection is the maximum of the lengths of this NESet
and that
. If this NESet
* is shorter than that
, thisElem
values are used to pad the result. If that
is shorter than this
* NESet
, thatElem
values are used to pad the result.
*/
def zipAll[O, U >: T](other: collection.Iterable[O], thisElem: U, otherElem: O): NESet[(U, O)] =
new NESet(toSet.zipAll(other, thisElem, otherElem))
/**
* Zips this NESet
with its indices.
*
* @return A new NESet
containing pairs consisting of all elements of this NESet
paired with their index. Indices start at 0.
*/
def zipWithIndex: NESet[(T, Int)] = new NESet(toSet.zipWithIndex)
def widen[U >: T]: NESet[U] = new NESet(toSet.toSet[U])
}
/**
* Companion object for class NESet
.
*/
object NESet extends NESetInstances {
/**
* Constructs a new NESet
given at least one element.
*
* @tparam T the type of the element contained in the new NESet
* @param firstElement the first element (with index 0) contained in this NESet
* @param otherElements a varargs of zero or more other elements (with index 1, 2, 3, ...) contained in this NESet
*/
@inline def apply[T](firstElement: T, otherElements: T*): NESet[T] = new NESet(otherElements.toSet + firstElement)
/**
* Variable argument extractor for NESet
s.
*
* @param NESet: the NESet
containing the elements to extract
* @return an Seq
containing this NESet
s elements, wrapped in a Some
*/
@inline def unapplySeq[T](NESet: NESet[T]): Some[Seq[T]] = Some(NESet.toSeq)
/**
* Optionally construct a NESet
containing the elements, if any, of a given Set
.
*
* @param set the Set
with which to construct a NESet
* @return a NESet
containing the elements of the given GenSeq
, if non-empty, wrapped in
* a Some
; else None
if the GenSeq
is empty
*/
@inline def from[T](set: scala.collection.immutable.Set[T]): Option[NESet[T]] =
set.headOption match {
case None => None
case Some(_) => Some(new NESet(set))
}
@inline def unsafeFrom[T](set: scala.collection.immutable.Set[T]): NESet[T] = {
require(set.nonEmpty)
new NESet(set)
}
implicit final class OptionOps[A](private val option: Option[NESet[A]]) extends AnyVal {
@inline def fromNESet: Set[A] = if (option.isEmpty) Set.empty else option.get.toSet
}
@inline implicit def asIterable[A](ne: NESet[A]): IterableOnce[A] = ne.toIterable
}