KT-33761 Add reduceOrNull
This commit is contained in:
committed by
Ilya Gorbunov
parent
39e1b24c2c
commit
f5d696d3c4
@@ -12731,6 +12731,141 @@ public inline fun CharArray.reduceIndexed(operation: (index: Int, acc: Char, Cha
|
|||||||
return accumulator
|
return accumulator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun <S, T : S> Array<out T>.reduceOrNull(operation: (acc: S, T) -> S): S? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator: S = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun ByteArray.reduceOrNull(operation: (acc: Byte, Byte) -> Byte): Byte? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun ShortArray.reduceOrNull(operation: (acc: Short, Short) -> Short): Short? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun IntArray.reduceOrNull(operation: (acc: Int, Int) -> Int): Int? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun LongArray.reduceOrNull(operation: (acc: Long, Long) -> Long): Long? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun FloatArray.reduceOrNull(operation: (acc: Float, Float) -> Float): Float? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun DoubleArray.reduceOrNull(operation: (acc: Double, Double) -> Double): Double? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun BooleanArray.reduceOrNull(operation: (acc: Boolean, Boolean) -> Boolean): Boolean? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun CharArray.reduceOrNull(operation: (acc: Char, Char) -> Char): Char? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value.
|
* Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1866,6 +1866,21 @@ public inline fun <S, T : S> Iterable<T>.reduceIndexed(operation: (index: Int, a
|
|||||||
return accumulator
|
return accumulator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the collection is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun <S, T : S> Iterable<T>.reduceOrNull(operation: (acc: S, T) -> S): S? {
|
||||||
|
val iterator = this.iterator()
|
||||||
|
if (!iterator.hasNext()) return null
|
||||||
|
var accumulator: S = iterator.next()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
accumulator = operation(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.
|
* Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1382,6 +1382,23 @@ public inline fun <S, T : S> Sequence<T>.reduceIndexed(operation: (index: Int, a
|
|||||||
return accumulator
|
return accumulator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the sequence is empty.
|
||||||
|
*
|
||||||
|
* The operation is _terminal_.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun <S, T : S> Sequence<T>.reduceOrNull(operation: (acc: S, T) -> S): S? {
|
||||||
|
val iterator = this.iterator()
|
||||||
|
if (!iterator.hasNext()) return null
|
||||||
|
var accumulator: S = iterator.next()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
accumulator = operation(accumulator, iterator.next())
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the sum of all values produced by [selector] function applied to each element in the sequence.
|
* Returns the sum of all values produced by [selector] function applied to each element in the sequence.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1195,6 +1195,21 @@ public inline fun CharSequence.reduceIndexed(operation: (index: Int, acc: Char,
|
|||||||
return accumulator
|
return accumulator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first character and applying [operation] from left to right to current accumulator value and each character. Returns null if the char sequence is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public inline fun CharSequence.reduceOrNull(operation: (acc: Char, Char) -> Char): Char? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accumulates value starting with last character and applying [operation] from right to left to each character and current accumulator value.
|
* Accumulates value starting with last character and applying [operation] from right to left to each character and current accumulator value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5618,6 +5618,74 @@ public inline fun UShortArray.reduceIndexed(operation: (index: Int, acc: UShort,
|
|||||||
return accumulator
|
return accumulator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
@kotlin.internal.InlineOnly
|
||||||
|
public inline fun UIntArray.reduceOrNull(operation: (acc: UInt, UInt) -> UInt): UInt? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
@kotlin.internal.InlineOnly
|
||||||
|
public inline fun ULongArray.reduceOrNull(operation: (acc: ULong, ULong) -> ULong): ULong? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
@kotlin.internal.InlineOnly
|
||||||
|
public inline fun UByteArray.reduceOrNull(operation: (acc: UByte, UByte) -> UByte): UByte? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
@kotlin.internal.InlineOnly
|
||||||
|
public inline fun UShortArray.reduceOrNull(operation: (acc: UShort, UShort) -> UShort): UShort? {
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value.
|
* Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1006,6 +1006,20 @@ class ArraysTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun reduceOrNull() {
|
||||||
|
expect(-4) { intArrayOf(1, 2, 3).reduceOrNull { a, b -> a - b } }
|
||||||
|
expect(-4.toLong()) { longArrayOf(1, 2, 3).reduceOrNull { a, b -> a - b } }
|
||||||
|
expect(-4F) { floatArrayOf(1F, 2F, 3F).reduceOrNull { a, b -> a - b } }
|
||||||
|
expect(-4.0) { doubleArrayOf(1.0, 2.0, 3.0).reduceOrNull { a, b -> a - b } }
|
||||||
|
expect('3') { charArrayOf('1', '3', '2').reduceOrNull { a, b -> if (a > b) a else b } }
|
||||||
|
expect(false) { booleanArrayOf(true, true, false).reduceOrNull { a, b -> a && b } }
|
||||||
|
expect(true) { booleanArrayOf(true, true).reduceOrNull { a, b -> a && b } }
|
||||||
|
expect(0.toByte()) { byteArrayOf(3, 2, 1).reduceOrNull { a, b -> (a - b).toByte() } }
|
||||||
|
expect(0.toShort()) { shortArrayOf(3, 2, 1).reduceOrNull { a, b -> (a - b).toShort() } }
|
||||||
|
|
||||||
|
expect(null, { intArrayOf().reduceOrNull { a, b -> a + b } })
|
||||||
|
}
|
||||||
|
|
||||||
@Test fun reduceRight() {
|
@Test fun reduceRight() {
|
||||||
expect(2) { intArrayOf(1, 2, 3).reduceRight { a, b -> a - b } }
|
expect(2) { intArrayOf(1, 2, 3).reduceRight { a, b -> a - b } }
|
||||||
expect(2.toLong()) { longArrayOf(1, 2, 3).reduceRight { a, b -> a - b } }
|
expect(2.toLong()) { longArrayOf(1, 2, 3).reduceRight { a, b -> a - b } }
|
||||||
|
|||||||
@@ -315,6 +315,15 @@ class CollectionTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun reduceOrNull() {
|
||||||
|
expect("1234") {
|
||||||
|
val list = listOf("1", "2", "3", "4")
|
||||||
|
list.reduceOrNull { a, b -> a + b }
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(null, { arrayListOf<Int>().reduceOrNull { a, b -> a + b } })
|
||||||
|
}
|
||||||
|
|
||||||
@Test fun reduceRight() {
|
@Test fun reduceRight() {
|
||||||
expect("1234") {
|
expect("1234") {
|
||||||
val list = listOf("1", "2", "3", "4")
|
val list = listOf("1", "2", "3", "4")
|
||||||
|
|||||||
@@ -379,6 +379,10 @@ public class SequenceTest {
|
|||||||
assertEquals(expected_, b.toList())
|
assertEquals(expected_, b.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun reduceOrNullOnEmpty() {
|
||||||
|
expect(null, { sequenceOf<Int>().reduceOrNull { acc, i -> acc + i } })
|
||||||
|
}
|
||||||
|
|
||||||
@Test fun minusElement() = testMinus(expected = listOf("foo", "bar")) { it - "bar" - "zoo" }
|
@Test fun minusElement() = testMinus(expected = listOf("foo", "bar")) { it - "bar" - "zoo" }
|
||||||
@Test fun minusCollection() = testMinus { it - listOf("bar", "zoo") }
|
@Test fun minusCollection() = testMinus { it - listOf("bar", "zoo") }
|
||||||
@Test fun minusArray() = testMinus { it - arrayOf("bar", "zoo") }
|
@Test fun minusArray() = testMinus { it - arrayOf("bar", "zoo") }
|
||||||
|
|||||||
@@ -1281,6 +1281,13 @@ class StringTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun reduceOrNull() = withOneCharSequenceArg { arg1 ->
|
||||||
|
// get the smallest character(by char value)
|
||||||
|
assertEquals('a', arg1("bacfd").reduceOrNull { v, c -> if (v > c) c else v })
|
||||||
|
|
||||||
|
expect(null, { arg1("").reduceOrNull { _, _ -> '\n' } })
|
||||||
|
}
|
||||||
|
|
||||||
@Test fun groupBy() = withOneCharSequenceArg("abAbaABcD") { data ->
|
@Test fun groupBy() = withOneCharSequenceArg("abAbaABcD") { data ->
|
||||||
// group characters by their case
|
// group characters by their case
|
||||||
val result = data.groupBy { it.isAsciiUpperCase() }
|
val result = data.groupBy { it.isAsciiUpperCase() }
|
||||||
|
|||||||
@@ -840,6 +840,67 @@ object Aggregates : TemplateGroupBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val f_reduceOrNull = fn("reduceOrNull(operation: (acc: T, T) -> T)") {
|
||||||
|
include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences)
|
||||||
|
} builder {
|
||||||
|
since("1.3")
|
||||||
|
annotation("@ExperimentalStdlibApi")
|
||||||
|
inline()
|
||||||
|
specialFor(ArraysOfUnsigned) { inlineOnly() }
|
||||||
|
|
||||||
|
doc { "Accumulates value starting with the first ${f.element} and applying [operation] from left to right to current accumulator value and each ${f.element}. Returns null if the ${f.collection} is empty." }
|
||||||
|
returns("T?")
|
||||||
|
body {
|
||||||
|
"""
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
|
||||||
|
var accumulator = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val f_reduceOrNullSuper = fn("reduceOrNull(operation: (acc: S, T) -> S)") {
|
||||||
|
include(ArraysOfObjects, Iterables, Sequences)
|
||||||
|
} builder {
|
||||||
|
since("1.3")
|
||||||
|
annotation("@ExperimentalStdlibApi")
|
||||||
|
inline()
|
||||||
|
|
||||||
|
doc { "Accumulates value starting with the first ${f.element} and applying [operation] from left to right to current accumulator value and each ${f.element}. Returns null if the ${f.collection} is empty." }
|
||||||
|
typeParam("S")
|
||||||
|
typeParam("T : S")
|
||||||
|
returns("S?")
|
||||||
|
body {
|
||||||
|
"""
|
||||||
|
val iterator = this.iterator()
|
||||||
|
if (!iterator.hasNext()) return null
|
||||||
|
|
||||||
|
var accumulator: S = iterator.next()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
accumulator = operation(accumulator, iterator.next())
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
body(ArraysOfObjects) {
|
||||||
|
"""
|
||||||
|
if (isEmpty())
|
||||||
|
return null
|
||||||
|
|
||||||
|
var accumulator: S = this[0]
|
||||||
|
for (index in 1..lastIndex) {
|
||||||
|
accumulator = operation(accumulator, this[index])
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val f_reduceRight = fn("reduceRight(operation: (T, acc: T) -> T)") {
|
val f_reduceRight = fn("reduceRight(operation: (T, acc: T) -> T)") {
|
||||||
include(CharSequences, ArraysOfPrimitives, ArraysOfUnsigned)
|
include(CharSequences, ArraysOfPrimitives, ArraysOfUnsigned)
|
||||||
} builder {
|
} builder {
|
||||||
|
|||||||
Reference in New Issue
Block a user