windowed function: add default parameters, drop or keep partial windows, KEEP-11
Make step default to 1. Add partialWindows boolean parameter defaulting to false to control whether to keep partial windows in the end.
This commit is contained in:
@@ -1809,7 +1809,7 @@ public fun <T : Any> List<T?>.requireNoNulls(): List<T> {
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T> Iterable<T>.chunked(size: Int): List<List<T>> {
|
||||
return windowed(size, size)
|
||||
return windowed(size, size, partialWindows = true)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1828,7 +1828,7 @@ public fun <T> Iterable<T>.chunked(size: Int): List<List<T>> {
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T, R> Iterable<T>.chunked(size: Int, transform: (List<T>) -> R): List<R> {
|
||||
return windowed(size, size, transform)
|
||||
return windowed(size, size, partialWindows = true, transform = transform)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2021,25 +2021,29 @@ public inline fun <T> Collection<T>.plusElement(element: T): List<T> {
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this collection.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.takeWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T> Iterable<T>.windowed(size: Int, step: Int): List<List<T>> {
|
||||
public fun <T> Iterable<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false): List<List<T>> {
|
||||
checkWindowSizeStep(size, step)
|
||||
if (this is RandomAccess && this is List) {
|
||||
val thisSize = this.size
|
||||
val result = ArrayList<List<T>>((thisSize + step - 1) / step)
|
||||
var index = 0
|
||||
while (index < thisSize) {
|
||||
result.add(List(size.coerceAtMost(thisSize - index)) { this[it + index] })
|
||||
val windowSize = size.coerceAtMost(thisSize - index)
|
||||
if (windowSize < size && !partialWindows) break
|
||||
result.add(List(windowSize) { this[it + index] })
|
||||
index += step
|
||||
}
|
||||
return result
|
||||
}
|
||||
val result = ArrayList<List<T>>()
|
||||
windowedIterator(iterator(), size, step, dropTrailing = false, reuseBuffer = false).forEach {
|
||||
windowedIterator(iterator(), size, step, partialWindows, reuseBuffer = false).forEach {
|
||||
result.add(it)
|
||||
}
|
||||
return result
|
||||
@@ -2056,12 +2060,14 @@ public fun <T> Iterable<T>.windowed(size: Int, step: Int): List<List<T>> {
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this collection.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.averageWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T, R> Iterable<T>.windowed(size: Int, step: Int, transform: (List<T>) -> R): List<R> {
|
||||
public fun <T, R> Iterable<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false, transform: (List<T>) -> R): List<R> {
|
||||
checkWindowSizeStep(size, step)
|
||||
if (this is RandomAccess && this is List) {
|
||||
val thisSize = this.size
|
||||
@@ -2070,13 +2076,14 @@ public fun <T, R> Iterable<T>.windowed(size: Int, step: Int, transform: (List<T>
|
||||
var index = 0
|
||||
while (index < thisSize) {
|
||||
window.move(index, (index + size).coerceAtMost(thisSize))
|
||||
if (!partialWindows && window.size < size) break
|
||||
result.add(transform(window))
|
||||
index += step
|
||||
}
|
||||
return result
|
||||
}
|
||||
val result = ArrayList<R>()
|
||||
windowedIterator(iterator(), size, step, dropTrailing = false, reuseBuffer = true).forEach {
|
||||
windowedIterator(iterator(), size, step, partialWindows, reuseBuffer = true).forEach {
|
||||
result.add(transform(it))
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -1344,7 +1344,7 @@ public fun <T : Any> Sequence<T?>.requireNoNulls(): Sequence<T> {
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T> Sequence<T>.chunked(size: Int): Sequence<List<T>> {
|
||||
return windowed(size, size)
|
||||
return windowed(size, size, partialWindows = true)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1365,7 +1365,7 @@ public fun <T> Sequence<T>.chunked(size: Int): Sequence<List<T>> {
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T, R> Sequence<T>.chunked(size: Int, transform: (List<T>) -> R): Sequence<R> {
|
||||
return windowed(size, size, transform)
|
||||
return windowed(size, size, partialWindows = true, transform = transform)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1546,13 +1546,15 @@ public inline fun <T> Sequence<T>.plusElement(element: T): Sequence<T> {
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.takeWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T> Sequence<T>.windowed(size: Int, step: Int): Sequence<List<T>> {
|
||||
return windowedSequence(size, step, dropTrailing = false, reuseBuffer = false)
|
||||
public fun <T> Sequence<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false): Sequence<List<T>> {
|
||||
return windowedSequence(size, step, partialWindows, reuseBuffer = false)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1566,13 +1568,15 @@ public fun <T> Sequence<T>.windowed(size: Int, step: Int): Sequence<List<T>> {
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.averageWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T, R> Sequence<T>.windowed(size: Int, step: Int, transform: (List<T>) -> R): Sequence<R> {
|
||||
return windowedSequence(size, step, dropTrailing = false, reuseBuffer = true).map(transform)
|
||||
public fun <T, R> Sequence<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false, transform: (List<T>) -> R): Sequence<R> {
|
||||
return windowedSequence(size, step, partialWindows, reuseBuffer = true).map(transform)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1121,7 +1121,7 @@ public inline fun CharSequence.sumByDouble(selector: (Char) -> Double): Double {
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun CharSequence.chunked(size: Int): List<String> {
|
||||
return windowed(size, size)
|
||||
return windowed(size, size, partialWindows = true)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1140,7 +1140,7 @@ public fun CharSequence.chunked(size: Int): List<String> {
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <R> CharSequence.chunked(size: Int, transform: (CharSequence) -> R): List<R> {
|
||||
return windowed(size, size, transform)
|
||||
return windowed(size, size, partialWindows = true, transform = transform)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1173,7 +1173,7 @@ public fun CharSequence.chunkedSequence(size: Int): Sequence<String> {
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <R> CharSequence.chunkedSequence(size: Int, transform: (CharSequence) -> R): Sequence<R> {
|
||||
return windowedSequence(size, size, transform)
|
||||
return windowedSequence(size, size, partialWindows = true, transform = transform)
|
||||
}
|
||||
|
||||
@Deprecated("Use zipWithNext instead", ReplaceWith("zipWithNext()"))
|
||||
@@ -1233,13 +1233,15 @@ public inline fun String.partition(predicate: (Char) -> Boolean): Pair<String, S
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this char sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.takeWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun CharSequence.windowed(size: Int, step: Int): List<String> {
|
||||
return windowed(size, step) { it.toString() }
|
||||
public fun CharSequence.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false): List<String> {
|
||||
return windowed(size, step, partialWindows) { it.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1253,18 +1255,22 @@ public fun CharSequence.windowed(size: Int, step: Int): List<String> {
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this char sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.averageWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <R> CharSequence.windowed(size: Int, step: Int, transform: (CharSequence) -> R): List<R> {
|
||||
public fun <R> CharSequence.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false, transform: (CharSequence) -> R): List<R> {
|
||||
checkWindowSizeStep(size, step)
|
||||
val thisSize = this.length
|
||||
val result = ArrayList<R>((thisSize + step - 1) / step)
|
||||
var index = 0
|
||||
while (index < thisSize) {
|
||||
result.add(transform(subSequence(index, (index + size).coerceAtMost(thisSize))))
|
||||
val end = index + size
|
||||
val coercedEnd = if (end > thisSize) { if (partialWindows) thisSize else break } else end
|
||||
result.add(transform(subSequence(index, coercedEnd)))
|
||||
index += step
|
||||
}
|
||||
return result
|
||||
@@ -1279,13 +1285,15 @@ public fun <R> CharSequence.windowed(size: Int, step: Int, transform: (CharSeque
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this char sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.takeWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun CharSequence.windowedSequence(size: Int, step: Int): Sequence<String> {
|
||||
return windowedSequence(size, step) { it.toString() }
|
||||
public fun CharSequence.windowedSequence(size: Int, step: Int = 1, partialWindows: Boolean = false): Sequence<String> {
|
||||
return windowedSequence(size, step, partialWindows) { it.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1299,14 +1307,17 @@ public fun CharSequence.windowedSequence(size: Int, step: Int): Sequence<String>
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this char sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.averageWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <R> CharSequence.windowedSequence(size: Int, step: Int, transform: (CharSequence) -> R): Sequence<R> {
|
||||
public fun <R> CharSequence.windowedSequence(size: Int, step: Int = 1, partialWindows: Boolean = false, transform: (CharSequence) -> R): Sequence<R> {
|
||||
checkWindowSizeStep(size, step)
|
||||
return (indices step step).asSequence().map { index -> transform(subSequence(index, (index + size).coerceAtMost(length))) }
|
||||
val windows = (if (partialWindows) indices else 0 until length - size + 1) step step
|
||||
return windows.asSequence().map { index -> transform(subSequence(index, (index + size).coerceAtMost(length))) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,12 +27,12 @@ internal fun checkWindowSizeStep(size: Int, step: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> Sequence<T>.windowedSequence(size: Int, step: Int, dropTrailing: Boolean, reuseBuffer: Boolean): Sequence<List<T>> {
|
||||
internal fun <T> Sequence<T>.windowedSequence(size: Int, step: Int, partialWindows: Boolean, reuseBuffer: Boolean): Sequence<List<T>> {
|
||||
checkWindowSizeStep(size, step)
|
||||
return Sequence { windowedIterator(iterator(), size, step, dropTrailing, reuseBuffer) }
|
||||
return Sequence { windowedIterator(iterator(), size, step, partialWindows, reuseBuffer) }
|
||||
}
|
||||
|
||||
internal fun <T> windowedIterator(iterator: Iterator<T>, size: Int, step: Int, dropTrailing: Boolean, reuseBuffer: Boolean): Iterator<List<T>> {
|
||||
internal fun <T> windowedIterator(iterator: Iterator<T>, size: Int, step: Int, partialWindows: Boolean, reuseBuffer: Boolean): Iterator<List<T>> {
|
||||
if (!iterator.hasNext()) return EmptyIterator
|
||||
return buildIterator<List<T>> {
|
||||
val gap = step - size
|
||||
@@ -49,7 +49,7 @@ internal fun <T> windowedIterator(iterator: Iterator<T>, size: Int, step: Int, d
|
||||
}
|
||||
}
|
||||
if (buffer.isNotEmpty()) {
|
||||
if (!dropTrailing || buffer.size == size) yield(buffer)
|
||||
if (partialWindows || buffer.size == size) yield(buffer)
|
||||
}
|
||||
} else {
|
||||
val buffer = RingBuffer<T>(size)
|
||||
@@ -60,7 +60,7 @@ internal fun <T> windowedIterator(iterator: Iterator<T>, size: Int, step: Int, d
|
||||
buffer.removeFirst(step)
|
||||
}
|
||||
}
|
||||
if (!dropTrailing) {
|
||||
if (partialWindows) {
|
||||
while (buffer.size > step) {
|
||||
yield(if (reuseBuffer) buffer else ArrayList(buffer))
|
||||
buffer.removeFirst(step)
|
||||
|
||||
Reference in New Issue
Block a user