Integrated contributed non-recursive implementation of permutations,
combinations, subsets, by EastSun. Also gave mutable Seqs an in-place transform method like the one Map has. And couldn't resist slightly reformulating a few set methods, because how can we settle for "forall(that.contains)" when we could have "this forall that". (Which is also what normal people hear when we talk about sets.) Closes #4060, #3644, review by moors. git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@24042 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
parent
1e2ef90b5f
commit
8cf68bbadf
|
@ -372,18 +372,127 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self =>
|
|||
* @return An Iterator which traverses the distinct permutations of this $coll.
|
||||
* @example `"abb".permutations = Iterator(abb, bab, bba)`
|
||||
*/
|
||||
def permutations: Iterator[Repr] = {
|
||||
val seen = mutable.HashSet[A]()
|
||||
val xs = thisCollection.toIndexedSeq
|
||||
def permutations: Iterator[Repr] =
|
||||
if (isEmpty) Iterator(repr)
|
||||
else new PermutationsItr
|
||||
|
||||
if (xs.isEmpty) Iterator.empty
|
||||
else if (xs.tail.isEmpty) Iterator(repr)
|
||||
else xs.indices collect {
|
||||
case idx if !seen(xs(idx)) =>
|
||||
seen += xs(idx)
|
||||
val rest = (xs take idx) ++ (xs drop (idx + 1))
|
||||
rest.permutations map (newBuilder += xs(idx) ++= _ result)
|
||||
} reduceLeft (_ ++ _)
|
||||
/** Iterates over combinations.
|
||||
*
|
||||
* @return An Iterator which traverses the possible n-element combinations of this $coll.
|
||||
* @example `"abbbc".combinations(2) = Iterator(ab, ac, bb, bc)`
|
||||
*/
|
||||
def combinations(n: Int): Iterator[Repr] =
|
||||
if (n < 0 || n > size) Iterator.empty
|
||||
else new CombinationsItr(n)
|
||||
|
||||
private class PermutationsItr extends Iterator[Repr] {
|
||||
private[this] val (elms, idxs) = init()
|
||||
private var _hasNext = true
|
||||
|
||||
def hasNext = _hasNext
|
||||
def next: Repr = {
|
||||
if (!hasNext)
|
||||
Iterator.empty.next
|
||||
|
||||
val result = (self.newBuilder ++= elms).result
|
||||
var i = idxs.length - 2
|
||||
while(i >= 0 && idxs(i) >= idxs(i+1))
|
||||
i -= 1
|
||||
|
||||
if (i < 0)
|
||||
_hasNext = false
|
||||
else {
|
||||
var j = idxs.length - 1
|
||||
while(idxs(j) <= idxs(i)) j -= 1
|
||||
swap(i,j)
|
||||
|
||||
val len = (idxs.length - i) / 2
|
||||
var k = 1
|
||||
while (k <= len) {
|
||||
swap(i+k, idxs.length - k)
|
||||
k += 1
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
private def swap(i: Int, j: Int) {
|
||||
var tmpI = idxs(i)
|
||||
idxs(i) = idxs(j)
|
||||
idxs(j) = tmpI
|
||||
var tmpE = elms(i)
|
||||
elms(i) = elms(j)
|
||||
elms(j) = tmpE
|
||||
}
|
||||
|
||||
private[this] def init() = {
|
||||
val m = mutable.HashMap[A, Int]()
|
||||
val (es, is) = thisCollection map (e => (e, m.getOrElseUpdate(e, m.size))) sortBy (_._2) unzip
|
||||
|
||||
(es.toBuffer, is.toArray)
|
||||
}
|
||||
}
|
||||
|
||||
private class CombinationsItr(n: Int) extends Iterator[Repr] {
|
||||
// generating all nums such that:
|
||||
// (1) nums(0) + .. + nums(length-1) = n
|
||||
// (2) 0 <= nums(i) <= cnts(i), where 0 <= i <= cnts.length-1
|
||||
private val (elms, cnts, nums) = init()
|
||||
private val offs = cnts.scanLeft(0)(_ + _)
|
||||
private var _hasNext = true
|
||||
|
||||
def hasNext = _hasNext
|
||||
def next: Repr = {
|
||||
if (!hasNext)
|
||||
Iterator.empty.next
|
||||
|
||||
/** Calculate this result. */
|
||||
val buf = self.newBuilder
|
||||
for(k <- 0 until nums.length; j <- 0 until nums(k))
|
||||
buf += elms(offs(k)+j)
|
||||
val res = buf.result
|
||||
|
||||
/** Prepare for the next call to next. */
|
||||
var idx = nums.length - 1
|
||||
while (idx >= 0 && nums(idx) == cnts(idx))
|
||||
idx -= 1
|
||||
|
||||
idx = nums.lastIndexWhere(_ > 0, idx - 1)
|
||||
|
||||
if (idx < 0)
|
||||
_hasNext = false
|
||||
else {
|
||||
var sum = nums.slice(idx + 1, nums.length).sum + 1
|
||||
nums(idx) -= 1
|
||||
for (k <- (idx+1) until nums.length) {
|
||||
nums(k) = sum min cnts(k)
|
||||
sum -= nums(k)
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
/** Rearrange seq to newSeq a0a0..a0a1..a1...ak..ak such that
|
||||
* seq.count(_ == aj) == cnts(j)
|
||||
*
|
||||
* @return (newSeq,cnts,nums)
|
||||
*/
|
||||
private def init(): (IndexedSeq[A], Array[Int], Array[Int]) = {
|
||||
val m = mutable.HashMap[A, Int]()
|
||||
|
||||
// e => (e, weight(e))
|
||||
val (es, is) = thisCollection map (e => (e, m.getOrElseUpdate(e, m.size))) sortBy (_._2) unzip
|
||||
val cs = new Array[Int](m.size)
|
||||
is foreach (i => cs(i) += 1)
|
||||
val ns = new Array[Int](cs.length)
|
||||
|
||||
var r = n
|
||||
0 until ns.length foreach { k =>
|
||||
ns(k) = r min cs(k)
|
||||
r -= ns(k)
|
||||
}
|
||||
(es.toIndexedSeq, cs, ns)
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns new $coll wih elements in reversed order.
|
||||
|
|
|
@ -141,7 +141,7 @@ self =>
|
|||
* @param elem the element to test for membership.
|
||||
* @return `true` if `elem` is contained in this set, `false` otherwise.
|
||||
*/
|
||||
def apply(elem: A): Boolean = contains(elem)
|
||||
def apply(elem: A): Boolean = this contains elem
|
||||
|
||||
/** Computes the intersection between this set and another set.
|
||||
*
|
||||
|
@ -149,7 +149,7 @@ self =>
|
|||
* @return a new set consisting of all elements that are both in this
|
||||
* set and in the given set `that`.
|
||||
*/
|
||||
def intersect(that: Set[A]): This = filter(that.contains)
|
||||
def intersect(that: Set[A]): This = this filter that
|
||||
|
||||
/** Computes the intersection between this set and another set.
|
||||
*
|
||||
|
@ -158,7 +158,7 @@ self =>
|
|||
* @return a new set consisting of all elements that are both in this
|
||||
* set and in the given set `that`.
|
||||
*/
|
||||
def &(that: Set[A]): This = intersect(that)
|
||||
def &(that: Set[A]): This = this intersect that
|
||||
|
||||
/** This method is an alias for `intersect`.
|
||||
* It computes an intersection with set `that`.
|
||||
|
@ -166,7 +166,8 @@ self =>
|
|||
*
|
||||
* @param that the set to intersect with
|
||||
*/
|
||||
@deprecated("use & instead") def ** (that: Set[A]): This = intersect(that)
|
||||
@deprecated("use & instead")
|
||||
def ** (that: Set[A]): This = &(that)
|
||||
|
||||
/** Computes the union between of set and another set.
|
||||
*
|
||||
|
@ -174,7 +175,7 @@ self =>
|
|||
* @return a new set consisting of all elements that are in this
|
||||
* set or in the given set `that`.
|
||||
*/
|
||||
def union(that: Set[A]): This = this.++(that)
|
||||
def union(that: Set[A]): This = this ++ that
|
||||
|
||||
/** Computes the union between this set and another set.
|
||||
*
|
||||
|
@ -183,7 +184,7 @@ self =>
|
|||
* @return a new set consisting of all elements that are in this
|
||||
* set or in the given set `that`.
|
||||
*/
|
||||
def | (that: Set[A]): This = union(that)
|
||||
def | (that: Set[A]): This = this union that
|
||||
|
||||
/** Computes the difference of this set and another set.
|
||||
*
|
||||
|
@ -191,7 +192,7 @@ self =>
|
|||
* @return a set containing those elements of this
|
||||
* set that are not also contained in the given set `that`.
|
||||
*/
|
||||
def diff(that: Set[A]): This = --(that)
|
||||
def diff(that: Set[A]): This = this -- that
|
||||
|
||||
/** The difference of this set and another set.
|
||||
*
|
||||
|
@ -200,7 +201,7 @@ self =>
|
|||
* @return a set containing those elements of this
|
||||
* set that are not also contained in the given set `that`.
|
||||
*/
|
||||
def &~(that: Set[A]): This = diff(that)
|
||||
def &~(that: Set[A]): This = this diff that
|
||||
|
||||
/** Tests whether this set is a subset of another set.
|
||||
*
|
||||
|
@ -208,7 +209,74 @@ self =>
|
|||
* @return `true` if this set is a subset of `that`, i.e. if
|
||||
* every element of this set is also an element of `that`.
|
||||
*/
|
||||
def subsetOf(that: Set[A]): Boolean = forall(that.contains)
|
||||
def subsetOf(that: Set[A]) = this forall that
|
||||
|
||||
/** An iterator over all subsets of this set of the given size.
|
||||
*
|
||||
* @param len the size of the subsets.
|
||||
* @return the iterator.
|
||||
*/
|
||||
def subsets(len: Int): Iterator[This] = {
|
||||
if (len < 0 || len > size) throw new IllegalArgumentException(len.toString)
|
||||
else new SubsetsItr(self.toIndexedSeq, len)
|
||||
}
|
||||
|
||||
/** An iterator over all subsets of this set.
|
||||
*
|
||||
* @return the iterator.
|
||||
*/
|
||||
def subsets: Iterator[This] = new Iterator[This] {
|
||||
private val elms = self.toIndexedSeq
|
||||
private var len = 0
|
||||
private var itr: Iterator[This] = Iterator.empty
|
||||
|
||||
def hasNext = len <= elms.size || itr.hasNext
|
||||
def next = {
|
||||
if (!itr.hasNext) {
|
||||
if (len > elms.size) Iterator.empty.next
|
||||
else {
|
||||
itr = new SubsetsItr(elms, len)
|
||||
len += 1
|
||||
}
|
||||
}
|
||||
|
||||
itr.next
|
||||
}
|
||||
}
|
||||
|
||||
/** An Iterator include all subsets containing exactly len elements.
|
||||
* If the elements in 'This' type is ordered, then the subsets will also be in the same order.
|
||||
* ListSet(1,2,3).subsets => {1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}}
|
||||
*
|
||||
* @author Eastsun
|
||||
* @date 2010.12.6
|
||||
*/
|
||||
private class SubsetsItr(elms: IndexedSeq[A], len: Int) extends Iterator[This] {
|
||||
private val idxs = Array.range(0, len+1)
|
||||
private var _hasNext = true
|
||||
idxs(len) = elms.size
|
||||
|
||||
def hasNext = _hasNext
|
||||
def next: This = {
|
||||
if (!hasNext) Iterator.empty.next
|
||||
|
||||
val buf = self.newBuilder
|
||||
idxs.slice(0, len) foreach (idx => buf += elms(idx))
|
||||
val result = buf.result
|
||||
|
||||
var i = len - 1
|
||||
while (i >= 0 && idxs(i) == idxs(i+1)-1) i -= 1
|
||||
|
||||
if (i < 0) _hasNext = false
|
||||
else {
|
||||
idxs(i) += 1
|
||||
for (j <- (i+1) until len)
|
||||
idxs(j) = idxs(j-1) + 1
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/** Defines the prefix of this object's `toString` representation.
|
||||
* @return a string representation which starts the result of `toString` applied to this set.
|
||||
|
|
|
@ -79,8 +79,6 @@ object BitSet extends BitSetFactory[BitSet] {
|
|||
else new BitSetN(elems)
|
||||
}
|
||||
|
||||
private val hashSeed = "BitSet".hashCode
|
||||
|
||||
class BitSet1(val elems: Long) extends BitSet {
|
||||
protected def nwords = 1
|
||||
protected def word(idx: Int) = if (idx == 0) elems else 0L
|
||||
|
|
|
@ -55,14 +55,14 @@ object IntMap {
|
|||
// develops. Case objects and custom equality don't mix without
|
||||
// careful handling.
|
||||
override def equals(that : Any) = that match {
|
||||
case (that : AnyRef) if (this eq that) => true;
|
||||
case (that : IntMap[_]) => false; // The only empty IntMaps are eq Nil
|
||||
case that => super.equals(that);
|
||||
case _: this.type => true
|
||||
case _: IntMap[_] => false // The only empty IntMaps are eq Nil
|
||||
case _ => super.equals(that)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private[immutable] case class Tip[+T](key : Int, value : T) extends IntMap[T]{
|
||||
def withValue[S](s : S) =
|
||||
def withValue[S](s: S) =
|
||||
if (s.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) this.asInstanceOf[IntMap.Tip[S]];
|
||||
else IntMap.Tip(key, s);
|
||||
}
|
||||
|
|
|
@ -28,4 +28,19 @@ trait SeqLike[A, +This <: SeqLike[A, This] with Seq[A]]
|
|||
* @throws IndexOutofBoundsException if the index is not valid.
|
||||
*/
|
||||
def update(idx: Int, elem: A)
|
||||
|
||||
/** Applies a transformation function to all values contained in this sequence.
|
||||
* The transformation function produces new values from existing elements.
|
||||
*
|
||||
* @param f the transformation to apply
|
||||
* @return the sequence itself.
|
||||
*/
|
||||
def transform(f: A => A): this.type = {
|
||||
var i = 0
|
||||
iterator foreach { el =>
|
||||
update(i, f(el))
|
||||
i += 1
|
||||
}
|
||||
this
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
object Test {
|
||||
val x = 1 to 10 toBuffer
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
x transform (_ * 2)
|
||||
assert(x.sum == (1 to 10).sum * 2)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue