Skip to content

Commit

Permalink
Merge pull request #10 from ryan-williams/h
Browse files Browse the repository at this point in the history
new iterators, factor out math/stats modules
  • Loading branch information
ryan-williams committed Aug 5, 2017
2 parents f6bae78 + 76d42ac commit 9a33b2a
Show file tree
Hide file tree
Showing 70 changed files with 1,589 additions and 1,890 deletions.
9 changes: 2 additions & 7 deletions build.sbt
@@ -1,12 +1,7 @@
name := "iterator"

version := "1.2.2"
version := "1.3.0"

addScala212

deps ++= Seq(
libs.value('commons_math),
kryo.value,
"com.chuusai" %% "shapeless" % "2.3.2",
libs.value('spire)
)
deps += spire
2 changes: 1 addition & 1 deletion project/plugins.sbt
@@ -1 +1 @@
addSbtPlugin("org.hammerlab" % "sbt-parent" % "2.0.1")
addSbtPlugin("org.hammerlab" % "sbt-parent" % "3.0.0")

This file was deleted.

17 changes: 17 additions & 0 deletions src/main/scala/org/hammerlab/iterator/DropEagerIterator.scala
@@ -0,0 +1,17 @@
package org.hammerlab.iterator

case class DropEagerIterator[T](it: Iterator[T]) {
def dropEager(n: Int): Iterator[T] = {
var idx = 0
while (it.hasNext && idx < n) {
it.next
idx += 1
}
it
}
}

object DropEagerIterator {
implicit def makeDropEagerIterator[T](it: Iterator[T]): DropEagerIterator[T] =
DropEagerIterator(it)
}
77 changes: 77 additions & 0 deletions src/main/scala/org/hammerlab/iterator/EitherIterator.scala
@@ -0,0 +1,77 @@
package org.hammerlab.iterator

import org.hammerlab.iterator.bulk.BufferedBulkIterator._
import scala.collection.mutable.ArrayBuffer

case class EitherIterator[T, U](it: BufferedIterator[Either[T, U]]) {

def findLeft: Option[T] =
it
.collect {
case Left(t) t
}
.buffered
.headOption

def groupByLeft: BufferedIterator[(T, Iterator[U])] = {

// Clear out any leading Rights
it
.collectwhile {
case Right(_) null
}
.toList

new SimpleBufferedIterator[(T, BufferedIterator[U])] {
var curLeft: Option[T] = None
var curRights = Iterator[U]().buffered
override protected def _advance: Option[(T, BufferedIterator[U])] = {

// Clear any unused elements from the previous rights/U's/"values" iterator
curRights.toList

it
.nextOption
.collect {
case Left(t)
curRights =
it
.collectwhile {
case Right(u) u
}

t curRights
case Right(u)
throw new IllegalStateException(
s"nextOption should not be a Right"
)
}
}
}
}

def roundUpRight: BufferedIterator[(Seq[T], U)] =
new SimpleBufferedIterator[(Seq[T], U)] {
override protected def _advance: Option[(Seq[T], U)] = {
val lefts = ArrayBuffer[T]()
while (true) {
it.headOption match {
case Some(Left(t))
it.next
lefts += t
case Some(Right(u))
it.next
return Some(lefts u)
case None
return None
}
}
???
}
}
}

object EitherIterator {
implicit def makeEitherIterator[T, U](it: Iterator[Either[T, U]]): EitherIterator[T, U] =
EitherIterator(it.buffered)
}
@@ -1,6 +1,6 @@
package org.hammerlab.iterator

import BufferedTakeWhileIterator._
import org.hammerlab.iterator.bulk.BufferedBulkIterator._

/**
* Group one sorted iterator with another, emitting an iterator of the latter's elements for each of the former's
Expand Down
@@ -1,5 +1,7 @@
package org.hammerlab.iterator

import scala.Range

/**
* Given an [[Iterator]] of [[Int]]s, collapse contiguous "ranges" of integers that are each 1 greater than their
* predecessor.
Expand All @@ -9,7 +11,8 @@ package org.hammerlab.iterator
*
* See RangeAccruingIteratorTest for more examples.
*/
class RangeAccruingIterator(it: Iterator[Int]) extends Iterator[Range] {
class RangeAccruingIterator(it: Iterator[Int])
extends Iterator[Range] {

var anchor = -1

Expand Down
17 changes: 17 additions & 0 deletions src/main/scala/org/hammerlab/iterator/SliceIterator.scala
@@ -0,0 +1,17 @@
package org.hammerlab.iterator

import org.hammerlab.iterator.DropEagerIterator._

case class SliceIterator[T](it: Iterator[T]) {
def sliceOpt(start: Option[Int], length: Option[Int]): Iterator[T] = {
start.foreach(it.dropEager)
length.map(it.take).getOrElse(it)
}
def sliceOpt(start: Int, length: Int): Iterator[T] = sliceOpt(Some(start), Some(length))
def sliceOpt(start: Option[Int], length: Int): Iterator[T] = sliceOpt(start, Some(length))
def sliceOpt(start: Int, length: Option[Int] = None): Iterator[T] = sliceOpt(Some(start), length)
}

object SliceIterator {
implicit def makeSliceIterator[T](it: Iterator[T]): SliceIterator[T] = SliceIterator(it)
}
@@ -0,0 +1,39 @@
package org.hammerlab.iterator.bulk

import org.hammerlab.iterator.SimpleBufferedIterator

/**
* Some smarter bulk operations on [[BufferedIterator]]s
*/
case class BufferedBulkIterator[T](it: BufferedIterator[T]) {
def takewhile(fn: T Boolean): SimpleBufferedIterator[T] =
new SimpleBufferedIterator[T] {
override protected def _advance: Option[T] =
if (it.hasNext && fn(it.head))
Some(it.next)
else
None
}

def dropwhile(fn: T Boolean): Unit =
while (it.hasNext && fn(it.head))
it.next

def collectwhile[U](pf: PartialFunction[T, U]): BufferedIterator[U] =
new SimpleBufferedIterator[U] {
override protected def _advance: Option[U] =
if (it.hasNext && pf.isDefinedAt(it.head))
Some(
pf(
it.next
)
)
else
None
}
}

object BufferedBulkIterator {
implicit def makeBufferedBulkWhileIterator[T](it: BufferedIterator[T]): BufferedBulkIterator[T] =
BufferedBulkIterator(it)
}
@@ -0,0 +1,71 @@
package org.hammerlab.iterator.range

import org.hammerlab.iterator.SimpleBufferedIterator

import scala.collection.mutable

case class OverlappingRangesIterator[T: Ordering](it: BufferedIterator[Range[T]]) {

type RangeT = (T, Option[T])

val = implicitly[Ordering[T]].lteq _

implicit val orderZippedRangeByEndOpt: Ordering[(Range[T], Int)] =
Ordering
.by[(Range[T], Int), Option[T]](_._1.endOpt)
.reverse

def joinOverlaps(other: Iterable[Range[T]]): Iterator[(Range[T], Vector[(Range[T], Int)])] =
joinOverlaps(other.iterator.buffered)

def joinOverlaps(other: BufferedIterator[Range[T]]): Iterator[(Range[T], Vector[(Range[T], Int)])] = {
val queue = mutable.PriorityQueue[(Range[T], Int)]()

val zippedOther =
other
.zipWithIndex
.buffered

new SimpleBufferedIterator[(Range[T], Vector[(Range[T], Int)])] {
override protected def _advance: Option[(Range[T], Vector[(Range[T], Int)])] =
it
.nextOption
.map {
elem
while (queue.headOption.exists(!_._1.∩(elem))) {
queue.dequeue()
}

while (
zippedOther
.headOption
.flatMap(_._1.endOpt)
.exists(≤(_, elem.start))
) {
zippedOther.next
}

while (
zippedOther
.headOption
.exists(_._1.∩(elem))
) {
queue.enqueue(zippedOther.next)
}

elem
queue
.toVector
.sortBy(_._2)
}
}
}
}

object OverlappingRangesIterator {
implicit def makeOverlappingRangesIteratorFromIterable[T: Ordering](it: Iterable[Range[T]]): OverlappingRangesIterator[T] =
OverlappingRangesIterator(it.iterator.buffered)

implicit def makeOverlappingRangesIterator[T: Ordering](it: Iterator[Range[T]]): OverlappingRangesIterator[T] =
OverlappingRangesIterator(it.buffered)
}
42 changes: 42 additions & 0 deletions src/main/scala/org/hammerlab/iterator/range/Range.scala
@@ -0,0 +1,42 @@
package org.hammerlab.iterator.range

case class Range[T](start: T, endOpt: Option[T]) {
def (right: Range[T])(implicit ord: Ordering[T]): Boolean = {
val = ord.lteq _
val Range(rightStart, rightEndOpt) = right
if (≤(start, rightStart))
!endOpt.exists(≤(_, rightStart))
else
!rightEndOpt.exists(≤(_, start))
}

override def toString: String =
s"[$start,${endOpt.getOrElse("")})"
}

object Range {
def apply[T](start: T, end: T): Range[T] = Range(start, Some(end))
def apply[T](start: T): Range[T] = Range(start, None)

implicit def endOptOrdering[T](implicit ord: Ordering[T]): Ordering[Option[T]] =
new Ordering[Option[T]] {
override def compare(x: Option[T], y: Option[T]): Int =
(x, y) match {
case (None, None) 0
case (None, _) -1
case (_, None) 1
case (Some(x), Some(y)) ord.compare(x, y)
}
}

implicit def orderByStartThenEnd[T: Ordering]: Ordering[Range[T]] = {

implicit val tupleOrdering =
Ordering.Tuple2[T, Option[T]]

Ordering.by[Range[T], (T, Option[T])] {
case Range(start, endOpt)
start endOpt
}
}
}
@@ -1,4 +1,6 @@
package org.hammerlab.iterator
package org.hammerlab.iterator.sliding

import org.hammerlab.iterator.SimpleBufferedIterator

case class Sliding2Iterator[T](it: BufferedIterator[T]) {
def sliding2Prev: Iterator[(Option[T], T)] =
Expand Down
@@ -1,4 +1,6 @@
package org.hammerlab.iterator
package org.hammerlab.iterator.sliding

import org.hammerlab.iterator.{ NextOptionIterator, SimpleBufferedIterator }

/**
* Given an [[Iterator[T]]], emit each element sandwiched between its preceding and succeeding elements.
Expand Down
@@ -1,4 +1,6 @@
package org.hammerlab.iterator
package org.hammerlab.iterator.sliding

import org.hammerlab.iterator.SimpleBufferedIterator

import scala.collection.mutable.ArrayBuffer

Expand Down

0 comments on commit 9a33b2a

Please sign in to comment.