diff --git a/libraries/stdlib/src/generated/_Arrays.kt b/libraries/stdlib/src/generated/_Arrays.kt index c5bddd02002..7f9bbf8b2fb 100644 --- a/libraries/stdlib/src/generated/_Arrays.kt +++ b/libraries/stdlib/src/generated/_Arrays.kt @@ -8782,6 +8782,105 @@ public inline fun ShortArray.fold(initial: R, operation: (R, Short) -> R): R return accumulator } +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun Array.foldIndexed(initial: R, operation: (Int, R, T) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun BooleanArray.foldIndexed(initial: R, operation: (Int, R, Boolean) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun ByteArray.foldIndexed(initial: R, operation: (Int, R, Byte) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun CharArray.foldIndexed(initial: R, operation: (Int, R, Char) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun DoubleArray.foldIndexed(initial: R, operation: (Int, R, Double) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun FloatArray.foldIndexed(initial: R, operation: (Int, R, Float) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun IntArray.foldIndexed(initial: R, operation: (Int, R, Int) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun LongArray.foldIndexed(initial: R, operation: (Int, R, Long) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun ShortArray.foldIndexed(initial: R, operation: (Int, R, Short) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + /** * Accumulates value starting with [initial] value and applying [operation] from right to left to each element and current accumulator value. */ @@ -8890,6 +8989,132 @@ public inline fun ShortArray.foldRight(initial: R, operation: (Short, R) -> return accumulator } +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun Array.foldRightIndexed(initial: R, operation: (Int, T, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun BooleanArray.foldRightIndexed(initial: R, operation: (Int, Boolean, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun ByteArray.foldRightIndexed(initial: R, operation: (Int, Byte, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun CharArray.foldRightIndexed(initial: R, operation: (Int, Char, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun DoubleArray.foldRightIndexed(initial: R, operation: (Int, Double, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun FloatArray.foldRightIndexed(initial: R, operation: (Int, Float, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun IntArray.foldRightIndexed(initial: R, operation: (Int, Int, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun LongArray.foldRightIndexed(initial: R, operation: (Int, Long, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun ShortArray.foldRightIndexed(initial: R, operation: (Int, Short, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + /** * Performs the given [action] on each element. */ @@ -10052,6 +10277,141 @@ public inline fun ShortArray.reduce(operation: (Short, Short) -> Short): Short { return accumulator } +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun Array.reduceIndexed(operation: (Int, S, T) -> S): S { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun BooleanArray.reduceIndexed(operation: (Int, Boolean, Boolean) -> Boolean): Boolean { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun ByteArray.reduceIndexed(operation: (Int, Byte, Byte) -> Byte): Byte { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun CharArray.reduceIndexed(operation: (Int, Char, Char) -> Char): Char { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun DoubleArray.reduceIndexed(operation: (Int, Double, Double) -> Double): Double { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun FloatArray.reduceIndexed(operation: (Int, Float, Float) -> Float): Float { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun IntArray.reduceIndexed(operation: (Int, Int, Int) -> Int): Int { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun LongArray.reduceIndexed(operation: (Int, Long, Long) -> Long): Long { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + */ +public inline fun ShortArray.reduceIndexed(operation: (Int, Short, Short) -> Short): Short { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + /** * Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value. */ @@ -10169,6 +10529,141 @@ public inline fun ShortArray.reduceRight(operation: (Short, Short) -> Short): Sh return accumulator } +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun Array.reduceRightIndexed(operation: (Int, T, S) -> S): S { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator: S = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun BooleanArray.reduceRightIndexed(operation: (Int, Boolean, Boolean) -> Boolean): Boolean { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun ByteArray.reduceRightIndexed(operation: (Int, Byte, Byte) -> Byte): Byte { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun CharArray.reduceRightIndexed(operation: (Int, Char, Char) -> Char): Char { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun DoubleArray.reduceRightIndexed(operation: (Int, Double, Double) -> Double): Double { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun FloatArray.reduceRightIndexed(operation: (Int, Float, Float) -> Float): Float { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun IntArray.reduceRightIndexed(operation: (Int, Int, Int) -> Int): Int { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun LongArray.reduceRightIndexed(operation: (Int, Long, Long) -> Long): Long { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + */ +public inline fun ShortArray.reduceRightIndexed(operation: (Int, Short, Short) -> Short): Short { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + /** * Returns the sum of all values produced by [selector] function applied to each element in the array. */ diff --git a/libraries/stdlib/src/generated/_Collections.kt b/libraries/stdlib/src/generated/_Collections.kt index 88c6989aa03..e1a69455c1e 100644 --- a/libraries/stdlib/src/generated/_Collections.kt +++ b/libraries/stdlib/src/generated/_Collections.kt @@ -1351,6 +1351,17 @@ public inline fun Iterable.fold(initial: R, operation: (R, T) -> R): R return accumulator } +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original collection. + */ +public inline fun Iterable.foldIndexed(initial: R, operation: (Int, R, T) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + /** * Accumulates value starting with [initial] value and applying [operation] from right to left to each element and current accumulator value. */ @@ -1363,6 +1374,20 @@ public inline fun List.foldRight(initial: R, operation: (T, R) -> R): return accumulator } +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original list and current accumulator value. + */ +public inline fun List.foldRightIndexed(initial: R, operation: (Int, T, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + /** * Performs the given [action] on each element. */ @@ -1502,6 +1527,21 @@ public inline fun Iterable.reduce(operation: (S, T) -> S): S { return accumulator } +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original collection. + */ +public inline fun Iterable.reduceIndexed(operation: (Int, S, T) -> S): S { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + /** * Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value. */ @@ -1515,6 +1555,21 @@ public inline fun List.reduceRight(operation: (T, S) -> S): S { return accumulator } +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original list and current accumulator value. + */ +public inline fun List.reduceRightIndexed(operation: (Int, T, S) -> S): S { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator: S = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + /** * Returns the sum of all values produced by [selector] function applied to each element in the collection. */ diff --git a/libraries/stdlib/src/generated/_Sequences.kt b/libraries/stdlib/src/generated/_Sequences.kt index 19aeb0bf76e..b816fb3ae73 100644 --- a/libraries/stdlib/src/generated/_Sequences.kt +++ b/libraries/stdlib/src/generated/_Sequences.kt @@ -796,6 +796,17 @@ public inline fun Sequence.fold(initial: R, operation: (R, T) -> R): R return accumulator } +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original sequence. + */ +public inline fun Sequence.foldIndexed(initial: R, operation: (Int, R, T) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + /** * Performs the given [action] on each element. */ @@ -934,6 +945,21 @@ public inline fun Sequence.reduce(operation: (S, T) -> S): S { return accumulator } +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original sequence. + */ +public inline fun Sequence.reduceIndexed(operation: (Int, S, T) -> S): S { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + /** * Returns the sum of all values produced by [selector] function applied to each element in the sequence. */ diff --git a/libraries/stdlib/src/generated/_Strings.kt b/libraries/stdlib/src/generated/_Strings.kt index 2fc9d3eb5b6..f2acef0a189 100644 --- a/libraries/stdlib/src/generated/_Strings.kt +++ b/libraries/stdlib/src/generated/_Strings.kt @@ -831,6 +831,17 @@ public inline fun CharSequence.fold(initial: R, operation: (R, Char) -> R): return accumulator } +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each character with its index in the original char sequence. + */ +public inline fun CharSequence.foldIndexed(initial: R, operation: (Int, R, Char) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + /** * Accumulates value starting with [initial] value and applying [operation] from right to left to each character and current accumulator value. */ @@ -843,6 +854,20 @@ public inline fun CharSequence.foldRight(initial: R, operation: (Char, R) -> return accumulator } +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each character with its index in the original char sequence and current accumulator value. + */ +public inline fun CharSequence.foldRightIndexed(initial: R, operation: (Int, Char, R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + /** * Performs the given [action] on each character. */ @@ -975,6 +1000,21 @@ public inline fun CharSequence.reduce(operation: (Char, Char) -> Char): Char { return accumulator } +/** + * Accumulates value starting with the first character and applying [operation] from left to right + * to current accumulator value and each character with its index in the original char sequence. + */ +public inline fun CharSequence.reduceIndexed(operation: (Int, Char, Char) -> Char): Char { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var index = 1 + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + /** * Accumulates value starting with last character and applying [operation] from right to left to each character and current accumulator value. */ @@ -988,6 +1028,21 @@ public inline fun CharSequence.reduceRight(operation: (Char, Char) -> Char): Cha return accumulator } +/** + * Accumulates value starting with last character and applying [operation] from right to left + * to each character with its index in the original char sequence and current accumulator value. + */ +public inline fun CharSequence.reduceRightIndexed(operation: (Int, Char, Char) -> Char): Char { + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + /** * Returns the sum of all values produced by [selector] function applied to each character in the char sequence. */ diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index a8aa77e92df..a4cebbec7b0 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -619,6 +619,38 @@ class ArraysTest { + @test fun reduceIndexed() { + expect(-1) { intArrayOf(1, 2, 3).reduceIndexed { index, a, b -> index + a - b } } + expect(-1.toLong()) { longArrayOf(1, 2, 3).reduceIndexed { index, a, b -> index + a - b } } + expect(-1F) { floatArrayOf(1F, 2F, 3F).reduceIndexed { index, a, b -> index + a - b } } + expect(-1.0) { doubleArrayOf(1.0, 2.0, 3.0).reduceIndexed { index, a, b -> index + a - b } } + expect('2') { charArrayOf('1', '3', '2').reduceIndexed { index, a, b -> if (a > b && index == 1) a else b } } + expect(true) { booleanArrayOf(true, true, false).reduceIndexed { index, a, b -> a && b || index == 2 } } + expect(false) { booleanArrayOf(true, true).reduceIndexed { index, a, b -> a && b && index != 1 } } + expect(1.toByte()) { byteArrayOf(3, 2, 1).reduceIndexed { index, a, b -> if (index != 2) (a - b).toByte() else a.toByte() } } + expect(1.toShort()) { shortArrayOf(3, 2, 1).reduceIndexed { index, a, b -> if (index != 2) (a - b).toShort() else a.toShort() } } + + assertTrue(assertFails { + intArrayOf().reduceIndexed { index, a, b -> a + b } + } is UnsupportedOperationException) + } + + @test fun reduceRightIndexed() { + expect(1) { intArrayOf(1, 2, 3).reduceRightIndexed { index, a, b -> index + a - b } } + expect(1.toLong()) { longArrayOf(1, 2, 3).reduceRightIndexed { index, a, b -> index + a - b } } + expect(1F) { floatArrayOf(1F, 2F, 3F).reduceRightIndexed { index, a, b -> index + a - b } } + expect(1.0) { doubleArrayOf(1.0, 2.0, 3.0).reduceRightIndexed { index, a, b -> index + a - b } } + expect('2') { charArrayOf('1', '3', '2').reduceRightIndexed { index, a, b -> if (a > b && index == 0) a else b } } + expect(true) { booleanArrayOf(true, true, false).reduceRightIndexed { index, a, b -> a && b || index == 1 } } + expect(false) { booleanArrayOf(true, true).reduceRightIndexed { index, a, b -> a && b && index != 0 } } + expect(1.toByte()) { byteArrayOf(3, 2, 1).reduceRightIndexed { index, a, b -> if (index != 1) (a - b).toByte() else a.toByte() } } + expect(1.toShort()) { shortArrayOf(3, 2, 1).reduceRightIndexed { index, a, b -> if (index != 1) (a - b).toShort() else a.toShort() } } + + assertTrue(assertFails { + intArrayOf().reduceRightIndexed { index, a, b -> a + b } + } is UnsupportedOperationException) + } + @test fun reduce() { expect(-4) { intArrayOf(1, 2, 3).reduce { a, b -> a - b } } expect(-4.toLong()) { longArrayOf(1, 2, 3).reduce { a, b -> a - b } } diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt index 0ad2a01f31d..e667020b1e8 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -79,6 +79,63 @@ class CollectionTest { } } + @test fun foldIndexed() { + expect(42) { + val numbers = listOf(1, 2, 3, 4) + numbers.foldIndexed(0) { index, a, b -> index * (a + b) } + } + + expect(0) { + val numbers = arrayListOf() + numbers.foldIndexed(0) { index, a, b -> index * (a + b) } + } + + expect("11234") { + val numbers = listOf(1, 2, 3, 4) + numbers.map { it.toString() }.foldIndexed("") { index, a, b -> if (index == 0) a + b + b else a + b } + } + } + + @test fun foldIndexedWithDifferentTypes() { + expect(10) { + val numbers = listOf("a", "ab", "abc") + numbers.foldIndexed(1) { index, a, b -> a + b.length + index } + } + + expect("11223344") { + val numbers = listOf(1, 2, 3, 4) + numbers.foldIndexed("") { index, a, b -> a + b + (index + 1) } + } + } + + @test fun foldIndexedWithNonCommutativeOperation() { + expect(4) { + val numbers = listOf(1, 2, 3) + numbers.foldIndexed(7) { index, a, b -> index + a - b } + } + } + + @test fun foldRightIndexed() { + expect("12343210") { + val numbers = listOf(1, 2, 3, 4) + numbers.map { it.toString() }.foldRightIndexed("") { index, a, b -> a + b + index } + } + } + + @test fun foldRightIndexedWithDifferentTypes() { + expect("12343210") { + val numbers = listOf(1, 2, 3, 4) + numbers.foldRightIndexed("") { index, a, b -> "" + a + b + index } + } + } + + @test fun foldRightIndexedWithNonCommutativeOperation() { + expect(-4) { + val numbers = listOf(1, 2, 3) + numbers.foldRightIndexed(7) { index, a, b -> index + a - b } + } + } + @test fun fold() { // lets calculate the sum of some numbers expect(10) { @@ -160,6 +217,32 @@ class CollectionTest { assertEquals(listOf("something"), pair.second, "pair.second") } + @test fun reduceIndexed() { + expect("123") { + val list = listOf("1", "2", "3", "4") + list.reduceIndexed { index, a, b -> if (index == 3) a else a + b } + } + + // TODO replace with more accurate version when KT-5987 will be fixed + // failsWith(javaClass()) { + assertFails { + run { arrayListOf().reduceIndexed { index, a, b -> a + b } } + } + } + + @test fun reduceRightIndexed() { + expect("234") { + val list = listOf("1", "2", "3", "4") + list.reduceRightIndexed { index, a, b -> if (index == 0) b else a + b } + } + + // TODO replace with more accurate version when KT-5987 will be fixed + // failsWith(javaClass()) { + assertFails { + run { arrayListOf().reduceRightIndexed { index, a, b -> a + b } } + } + } + @test fun reduce() { expect("1234") { val list = listOf("1", "2", "3", "4") diff --git a/libraries/stdlib/test/text/StringTest.kt b/libraries/stdlib/test/text/StringTest.kt index 8c474e5b043..30cad8b35f2 100644 --- a/libraries/stdlib/test/text/StringTest.kt +++ b/libraries/stdlib/test/text/StringTest.kt @@ -859,6 +859,24 @@ class StringTest { assertEquals(data.toString(), data.foldRight("", { s, c -> "" + s + c })) } + @test fun reduceIndexed() = withOneCharSequenceArg { arg1 -> + // get the 3rd character + assertEquals('c', arg1("bacfd").reduceIndexed { index, v, c -> if (index == 2) c else v }) + + assertTrue(assertFails { + arg1("").reduceIndexed { index, a, b -> '\n' } + } is UnsupportedOperationException) + } + + @test fun reduceRightIndexed() = withOneCharSequenceArg { arg1 -> + // get the 3rd character + assertEquals('c', arg1("bacfd").reduceRightIndexed { index, c, v -> if (index == 2) c else v }) + + assertTrue(assertFails { + arg1("").reduceRightIndexed { index, a, b -> '\n' } + } is UnsupportedOperationException) + } + @test fun reduce() = withOneCharSequenceArg { arg1 -> // get the smallest character(by char value) assertEquals('a', arg1("bacfd").reduce { v, c -> if (v > c) c else v }) diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt index 1c51f0ec448..d36f39eabc3 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt @@ -349,6 +349,53 @@ fun aggregates(): List { body(Maps) { "return entries.maxWith(comparator)" } } + templates add f("foldIndexed(initial: R, operation: (Int, R, T) -> R)") { + inline(true) + + include(CharSequences) + doc { f -> + """ + Accumulates value starting with [initial] value and applying [operation] from left to right + to current accumulator value and each ${f.element} with its index in the original ${f.collection}. + """ + } + typeParam("R") + returns("R") + body { + """ + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator + """ + } + } + + templates add f("foldRightIndexed(initial: R, operation: (Int, T, R) -> R)") { + inline(true) + + only(CharSequences, Lists, ArraysOfObjects, ArraysOfPrimitives) + doc { f -> + """ + Accumulates value starting with [initial] value and applying [operation] from right to left + to each ${f.element} with its index in the original ${f.collection} and current accumulator value. + """ + } + typeParam("R") + returns("R") + body { + """ + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator + """ + } + } + templates add f("fold(initial: R, operation: (R, T) -> R)") { inline(true) @@ -384,6 +431,116 @@ fun aggregates(): List { } } + templates add f("reduceIndexed(operation: (Int, T, T) -> T)") { + inline(true) + include(CharSequences) + exclude(ArraysOfObjects, Iterables, Sequences) + + doc { f -> + """ + Accumulates value starting with the first ${f.element} and applying [operation] from left to right + to current accumulator value and each ${f.element} with its index in the original ${f.collection}. + """ + } + returns("T") + body { + """ + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + + var index = 1 + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator + """ + } + } + + templates add f("reduceIndexed(operation: (Int, S, T) -> S)") { + inline(true) + only(ArraysOfObjects, Iterables, Sequences) + + doc { f -> + """ + Accumulates value starting with the first ${f.element} and applying [operation] from left to right + to current accumulator value and each ${f.element} with its index in the original ${f.collection}. + """ + } + typeParam("S") + typeParam("T: S") + returns("S") + body { + """ + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced.") + + var index = 1 + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator + """ + } + } + + templates add f("reduceRightIndexed(operation: (Int, T, T) -> T)") { + inline(true) + + only(CharSequences, ArraysOfPrimitives) + doc { f -> + """ + Accumulates value starting with last ${f.element} and applying [operation] from right to left + to each ${f.element} with its index in the original ${f.collection} and current accumulator value. + """ + } + returns("T") + body { + """ + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + + return accumulator + """ + } + } + + templates add f("reduceRightIndexed(operation: (Int, T, S) -> S)") { + inline(true) + + only(Lists, ArraysOfObjects) + doc { f -> + """ + Accumulates value starting with last ${f.element} and applying [operation] from right to left + to each ${f.element} with its index in the original ${f.collection} and current accumulator value. + """ + } + typeParam("S") + typeParam("T: S") + returns("S") + body { + """ + var index = lastIndex + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced.") + + var accumulator: S = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + + return accumulator + """ + } + } templates add f("reduce(operation: (T, T) -> T)") { inline(true)