Created
August 8, 2018 20:34
-
-
Save leifwickland/968877800565b530fec795956a0096d1 to your computer and use it in GitHub Desktop.
scanFilter/scanFind
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object IndexedSeqSyntax { | |
@specialized(Specializable.Bits32AndUp) | |
implicit class IndexedSeqOps[T](ts: IndexedSeq[T]) { | |
/** | |
* Accumulates values, S, derived from T, and returns the first T, if any when p is true for S. | |
* | |
* It's kind of like a lazy conjunction of the standard library's `scan` and `find`. | |
* | |
* It could be implemented less efficiently as: | |
* ts.toIterator.zip(ts.toIterator.scanLeft(sz)(toS)).find(t => p(_._2)).map(_._1) | |
* | |
* @param z Initial value of the accumulated state. | |
* @param op Applied to the accumulated state and the element. | |
* @param p The predicate to satisfy against the accumulated state | |
* @tparam S The state which is accumulated | |
* @return The first T when p is satisfied, or None | |
*/ | |
def scanFind[S](z: S)(op: (S, T) => S)(p: S => Boolean): Option[T] = { | |
val len = ts.length | |
@annotation.tailrec | |
def loop(i: Int, s: S): Option[T] = { | |
if (i >= len) None | |
else { | |
val t = ts(i) | |
val newS = op(s, t) | |
if (p(newS)) Some(t) | |
else loop(i + 1, newS) | |
} | |
} | |
loop(0, z) | |
} | |
/** | |
* Accumulates values, S, derived from T, and returns all Ts for which `p` is true. | |
* | |
* It's kind of like a lazy conjunction of the standard library's `scan` and `filter`. | |
* | |
* It could be implemented less efficiently as: | |
* ts.toIterator.zip(ts.toIterator.scanLeft(sz)(toS)).filter(t => p(_._2)).map(_._1) | |
* | |
* @param z Initial value of the accumulated state. | |
* @param op Applied to the accumulated state and the element. | |
* @param p The predicate to satisfy against the accumulated state | |
* @tparam S The state which is accumulated | |
* @return All Ts when p is satisfied; possibly empty. | |
*/ | |
def scanFilter[S](z: S)(op: (S, T) => S)(p: S => Boolean): Vector[T] = { | |
val len = ts.length | |
val buffer = scala.collection.mutable.Buffer[T]() | |
@annotation.tailrec | |
def loop(i: Int, s: S): Vector[T] = { | |
if (i >= len) buffer.toVector | |
else { | |
val t = ts(i) | |
val newS = op(s, t) | |
if (p(newS)) { buffer += t } | |
loop(i + 1, newS) | |
} | |
} | |
loop(0, z) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment