All Downloads are FREE. Search and download functionalities are using the official Maven repository.

axle.Combinations.scala Maven / Gradle / Ivy

The newest version!
package axle

import scala.Stream.cons
import scala.Stream.empty
import scala.annotation.tailrec

import spire.implicits.IntAlgebra
import spire.implicits.eqOps

object Combinations {

  def apply[E: Manifest](pool: Seq[E], r: Int): Combinations[E] = new Combinations(pool, r)
}

class Combinations[E: Manifest](_pool: Seq[E], r: Int) extends Iterable[IndexedSeq[E]] {

  val pool: Array[E] = _pool.toList.toArray
  val n = pool.size

  if (r > n) {
    throw new IndexOutOfBoundsException()
  }

  lazy val _size = if (0 <= r && r <= n) (n.factorial / r.factorial / (n - r).factorial) else 0

  override def size: Int = _size

  @tailrec
  private[this] def loop3(indices0: Array[Int], i0: Int, broken0: Boolean): (Boolean, Int) =
    if (i0 >= 0 && !broken0) {
      val broken1 = (indices0(i0) != (i0 + n - r))
      loop3(indices0, if (broken1) i0 else (i0 - 1), broken1)
    } else {
      (broken0, i0)
    }

  def loop2(indices0: Array[Int]): (Stream[IndexedSeq[E]], Array[Int], Boolean) = {
    val (broken1, i0) = loop3(indices0, r - 1, false)
    if (!broken1) {
      (empty, indices0, true)
    } else {
      val indices1 = indices0.zipWithIndex.map({
        case (v, j) =>
          if (j === i0) {
            v + 1
          } else if (j >= (i0 + 1) && j < r) {
            (indices0(j - 1) + 1)
          } else {
            v
          }
      })
      val head = indices1.map(pool)
      val (tail, indices2, done) = loop2(indices1)
      (cons(head, tail), indices2, done)
    }
  }

  def loop1(indices0: Array[Int], done0: Boolean): Stream[IndexedSeq[E]] =
    if (done0) {
      empty
    } else {
      val (subStream, indices1, done1) = loop2(indices0)
      subStream ++ loop1(indices1, done1)
    }

  lazy val result: Stream[IndexedSeq[E]] = {
    val indices = (0 until r).toArray
    cons(indices.map(pool), loop1(indices, false))
  }

  def iterator: Iterator[IndexedSeq[E]] = result.iterator

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy