Merge pull request #32 from franckrasolo/master

#KT-1653 Fixed
This commit is contained in:
James Strachan
2012-03-28 11:03:07 -07:00
2 changed files with 173 additions and 51 deletions
+114 -51
View File
@@ -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())
}
}