@@ -3,61 +3,57 @@ package kotlin
|
||||
import kotlin.support.AbstractIterator
|
||||
import kotlin.support.FunctionIterator
|
||||
|
||||
import java.util.*
|
||||
import java.util.Iterator
|
||||
/**
|
||||
* Returns an iterator which invokes the function to calculate the next value on each iteration until the function returns *null*
|
||||
*
|
||||
* @includeFunction ../../test/iterators/IteratorsTest.kt fibonacci
|
||||
*/
|
||||
inline fun <T> iterate(nextFunction: () -> T?) : java.util.Iterator<T> = FunctionIterator(nextFunction)
|
||||
|
||||
/** Filters the iterator for all elements of a certain sub class */
|
||||
inline fun <T, R: T> java.util.Iterator<T>.filterIsInstance(klass: Class<R>): Iterator<R> = FilterIsIterator<T,R>(this, klass)
|
||||
/** Returns an iterator over elements that are instances of a given type *R* which is a subclass of *T* */
|
||||
inline fun <T, R: T> java.util.Iterator<T>.filterIsInstance(klass: Class<R>): java.util.Iterator<R> = FilterIsIterator<T,R>(this, klass)
|
||||
|
||||
private class FilterIsIterator<T, R :T>(val iter: java.util.Iterator<T>, val klass: Class<R>) : AbstractIterator<R>() {
|
||||
private class FilterIsIterator<T, R :T>(val iterator : java.util.Iterator<T>, val klass: Class<R>) : AbstractIterator<R>() {
|
||||
override protected fun computeNext(): R? {
|
||||
while (iter.hasNext()) {
|
||||
val next = iter.next()
|
||||
if (klass.isInstance(next)) {
|
||||
return next as R
|
||||
}
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
if (klass.isInstance(next)) return next as R
|
||||
}
|
||||
done()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a new lazy iterator containing all elements in this iteration which match the given predicate */
|
||||
inline fun <T> java.util.Iterator<T>.filter(predicate: (T)-> Boolean) : java.util.Iterator<T> {
|
||||
return FilterIterator(this, predicate)
|
||||
}
|
||||
/**
|
||||
* Returns an iterator over elements which match the given *predicate*
|
||||
*
|
||||
* @includeFunction ../../test/iterators/IteratorsTest.kt filterAndTakeWhileExtractTheElementsWithinRange
|
||||
*/
|
||||
inline fun <T> java.util.Iterator<T>.filter(predicate: (T) -> Boolean) : java.util.Iterator<T> = FilterIterator<T>(this, predicate)
|
||||
|
||||
private class FilterIterator<T>(val iter: java.util.Iterator<T>, val predicate: (T)-> Boolean) : AbstractIterator<T>() {
|
||||
private class FilterIterator<T>(val iterator : java.util.Iterator<T>, val predicate: (T)-> Boolean) : AbstractIterator<T>() {
|
||||
override protected fun computeNext(): T? {
|
||||
while (iter.hasNext()) {
|
||||
val element = iter.next()
|
||||
if ((predicate)(element)) {
|
||||
return element
|
||||
}
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
if ((predicate)(next)) return next
|
||||
}
|
||||
done()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a new lazy iterator containing all elements in this iteration which do not match the given predicate */
|
||||
inline fun <T> java.util.Iterator<T>.filterNot(predicate: (T)-> Boolean) : java.util.Iterator<T> {
|
||||
return filter {
|
||||
!predicate(it)
|
||||
}
|
||||
}
|
||||
/** Returns an iterator over elements which do not match the given *predicate* */
|
||||
inline fun <T> java.util.Iterator<T>.filterNot(predicate: (T) -> Boolean) : java.util.Iterator<T> = filter { !predicate(it) }
|
||||
|
||||
/** Returns a new lazy iterator containing all the non null elements in this iteration */
|
||||
/** Returns an iterator over non-*null* elements */
|
||||
inline fun <T> java.util.Iterator<T?>?.filterNotNull() : java.util.Iterator<T> = FilterNotNullIterator(this)
|
||||
|
||||
private class FilterNotNullIterator<T>(val iter: java.util.Iterator<T?>?) : AbstractIterator<T>() {
|
||||
override fun computeNext(): T? {
|
||||
if (iter != null) {
|
||||
while (iter.hasNext()) {
|
||||
val next = iter.next()
|
||||
if (next != null) {
|
||||
return next
|
||||
}
|
||||
private class FilterNotNullIterator<T>(val iterator : java.util.Iterator<T?>?) : AbstractIterator<T>() {
|
||||
override protected fun computeNext(): T? {
|
||||
if (iterator != null) {
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
if (next != null) return next
|
||||
}
|
||||
}
|
||||
done()
|
||||
@@ -65,21 +61,88 @@ private class FilterNotNullIterator<T>(val iter: java.util.Iterator<T?>?) : Abst
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a lazy iterator containing the result of transforming each item in the iteration to a one or more values which
|
||||
* are concatenated together into a single collection
|
||||
*/
|
||||
/*
|
||||
|
||||
TODO implement a lazy flatMap
|
||||
|
||||
inline fun <T, R> java.util.Iterator<T>.flatMap(transform: (T)-> java.util.Iterator<R>) : Collection<R> {
|
||||
return flatMapTo<>(ArrayList<R>(), transform)
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns an iterator which invokes the function to calculate the next value on each iteration until the function returns null
|
||||
* Returns an iterator obtained by applying *transform*, a function transforming an object of type *T* into an object of type *R*
|
||||
*
|
||||
* @includeFunction ../../test/iterators/IteratorsTest.kt mapAndTakeWhileExtractTheTransformedElements
|
||||
*/
|
||||
inline fun <T> iterate(nextFunction: () -> T?) : Iterator<T> = FunctionIterator(nextFunction)
|
||||
inline fun <T, R> java.util.Iterator<T>.map(transform: (T) -> R): java.util.Iterator<R> = MapIterator<T, R>(this, transform)
|
||||
|
||||
private class MapIterator<T, R>(val iterator : java.util.Iterator<T>, val transform: (T) -> R) : AbstractIterator<R>() {
|
||||
override protected fun computeNext() : R? = if (iterator.hasNext()) (transform)(iterator.next()) else { done(); null }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the concatenated results of transforming each element to one or more values
|
||||
*
|
||||
* @includeFunction ../../test/iterators/IteratorsTest.kt flatMapAndTakeExtractTheTransformedElements
|
||||
*/
|
||||
inline fun <T, R> java.util.Iterator<T>.flatMap(transform: (T) -> java.util.Iterator<R>): java.util.Iterator<R> = FlatMapIterator<T, R>(this, transform)
|
||||
|
||||
private class FlatMapIterator<T, R>(val iterator : java.util.Iterator<T>, val transform: (T) -> java.util.Iterator<R>) : AbstractIterator<R>() {
|
||||
var transformed: java.util.Iterator<R> = iterate<R> { null }
|
||||
|
||||
override protected fun computeNext() : R? {
|
||||
if (transformed.hasNext()) return transformed.next()
|
||||
if (iterator.hasNext()) {
|
||||
transformed = (transform)(iterator.next())
|
||||
return computeNext()
|
||||
}
|
||||
done()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator restricted to the first *n* elements
|
||||
*
|
||||
* @includeFunction ../../test/iterators/IteratorsTest.kt takeExtractsTheFirstNElements
|
||||
*/
|
||||
inline fun <T> java.util.Iterator<T>.take(n: Int): java.util.Iterator<T> {
|
||||
fun countTo(n: Int): (T) -> Boolean {
|
||||
var count = 0
|
||||
return { ++count; count <= n }
|
||||
}
|
||||
return takeWhile(countTo(n))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator restricted to the first elements that match the given *predicate*
|
||||
*
|
||||
* @includeFunction ../../test/iterators/IteratorsTest.kt filterAndTakeWhileExtractTheElementsWithinRange
|
||||
*/
|
||||
inline fun <T> java.util.Iterator<T>.takeWhile(predicate: (T) -> Boolean): java.util.Iterator<T> = TakeWhileIterator<T>(this, predicate)
|
||||
|
||||
private class TakeWhileIterator<T>(val iterator: java.util.Iterator<T>, val predicate: (T) -> Boolean) : AbstractIterator<T>() {
|
||||
override protected fun computeNext() : T? {
|
||||
if (iterator.hasNext()) {
|
||||
val item = iterator.next()
|
||||
if ((predicate)(item)) return item
|
||||
}
|
||||
done()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string from the first *n (= limit)* elements separated using the *separator* and using the given *prefix* and *postfix* if supplied
|
||||
*
|
||||
* @includeFunction ../../test/iterators/IteratorsTest.kt joinConcatenatesTheFirstNElementsAboveAThreshold
|
||||
*/
|
||||
inline fun <T> java.util.Iterator<T>.join(separator: String, prefix: String = "", postfix: String = "", limit: Int = 20) : String {
|
||||
val buffer = StringBuilder(prefix)
|
||||
var first = true; var count = 0
|
||||
for (element in this) {
|
||||
if (first) first = false else buffer.append(separator)
|
||||
if (++count <= limit) buffer.append(element) else break
|
||||
}
|
||||
if (count > limit) buffer.append("...")
|
||||
return buffer.append(postfix).toString().sure()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a comma-separated representation of no more than the first 10 elements
|
||||
*
|
||||
* @includeFunction ../../test/iterators/IteratorsTest.kt toStringJoinsNoMoreThanTheFirstTenElements
|
||||
*/
|
||||
inline fun <T> java.util.Iterator<T>.toString(): String = join(separator = ", ", limit = 10)
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package iterators
|
||||
|
||||
import kotlin.test.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class IteratorsTest {
|
||||
|
||||
private fun fibonacci(): java.util.Iterator<Int> {
|
||||
// fibonacci terms
|
||||
var index = 0; var a = 0; var b = 1
|
||||
return iterate<Int> { when (index++) { 0 -> a; 1 -> b; else -> { val result = a + b; a = b; b = result; result } } }
|
||||
}
|
||||
|
||||
Test fun filterAndTakeWhileExtractTheElementsWithinRange() {
|
||||
assertEquals(arrayList(144, 233, 377, 610, 987), fibonacci().filter { it > 100 }.takeWhile { it < 1000 }.toList())
|
||||
}
|
||||
|
||||
Test fun foldReducesTheFirstNElements() {
|
||||
val sum = { (a: Int, b: Int) -> a + b }
|
||||
assertEquals(arrayList(13, 21, 34, 55, 89).fold(0, sum), fibonacci().filter { it > 10 }.take(5).fold(0, sum))
|
||||
}
|
||||
|
||||
Test fun takeExtractsTheFirstNElements() {
|
||||
assertEquals(arrayList(0, 1, 1, 2, 3, 5, 8, 13, 21, 34), fibonacci().take(10).toList())
|
||||
}
|
||||
|
||||
Test fun mapAndTakeWhileExtractTheTransformedElements() {
|
||||
assertEquals(arrayList(0, 3, 3, 6, 9, 15), fibonacci().map { it * 3 }.takeWhile { (i: Int) -> i < 20 }.toList())
|
||||
}
|
||||
|
||||
Test fun flatMapAndTakeExtractTheTransformedElements() {
|
||||
fun intToBinaryDigits() = { (i: Int) ->
|
||||
val binary = Integer.toBinaryString(i).sure()
|
||||
var index = 0
|
||||
iterate<Char> { if (index < binary.length()) binary.get(index++) else null }
|
||||
}
|
||||
|
||||
val expected = arrayList(
|
||||
'0', // fibonacci(0) = 0
|
||||
'1', // fibonacci(1) = 1
|
||||
'1', // fibonacci(2) = 1
|
||||
'1', '0', // fibonacci(3) = 2
|
||||
'1', '1', // fibonacci(4) = 3
|
||||
'1', '0', '1' // fibonacci(5) = 5
|
||||
)
|
||||
|
||||
assertEquals(expected, fibonacci().flatMap<Int, Char>(intToBinaryDigits()).take(10).toList())
|
||||
}
|
||||
|
||||
Test fun joinConcatenatesTheFirstNElementsAboveAThreshold() {
|
||||
assertEquals("13, 21, 34, 55, 89, ...", fibonacci().filter { it > 10 }.join(separator = ", ", limit = 5))
|
||||
}
|
||||
|
||||
Test fun toStringJoinsNoMoreThanTheFirstTenElements() {
|
||||
assertEquals("0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...", fibonacci().toString())
|
||||
assertEquals("13, 21, 34, 55, 89, 144, 233, 377, 610, 987, ...", fibonacci().filter { it > 10 }.toString())
|
||||
assertEquals("144, 233, 377, 610, 987", fibonacci().filter { it > 100 }.takeWhile { it < 1000 }.toString())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user