Introduce firstNotNullOf and firstNotNullOfOrNull #KT-12109

This commit is contained in:
Abduqodiri Qurbonzoda
2021-03-11 18:08:26 +03:00
parent d4b3ae92cb
commit ff5b2404af
15 changed files with 342 additions and 0 deletions
@@ -2550,6 +2550,30 @@ public inline fun <T> kotlin.collections.Iterable<T>.first(predicate: (T) -> kot
public fun <T> kotlin.collections.List<T>.first(): T
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.Array<out T>.firstNotNullOf(transform: (T) -> R?): R
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.collections.Iterable<T>.firstNotNullOf(transform: (T) -> R?): R
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <K, V, R : kotlin.Any> kotlin.collections.Map<out K, V>.firstNotNullOf(transform: (kotlin.collections.Map.Entry<K, V>) -> R?): R
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.Array<out T>.firstNotNullOfOrNull(transform: (T) -> R?): R?
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.collections.Iterable<T>.firstNotNullOfOrNull(transform: (T) -> R?): R?
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <K, V, R : kotlin.Any> kotlin.collections.Map<out K, V>.firstNotNullOfOrNull(transform: (kotlin.collections.Map.Entry<K, V>) -> R?): R?
public fun <T> kotlin.Array<out T>.firstOrNull(): T?
public inline fun <T> kotlin.Array<out T>.firstOrNull(predicate: (T) -> kotlin.Boolean): T?
@@ -140,6 +140,14 @@ public fun <T> kotlin.sequences.Sequence<T>.first(): T
public inline fun <T> kotlin.sequences.Sequence<T>.first(predicate: (T) -> kotlin.Boolean): T
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.sequences.Sequence<T>.firstNotNullOf(transform: (T) -> R?): R
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.sequences.Sequence<T>.firstNotNullOfOrNull(transform: (T) -> R?): R?
public fun <T> kotlin.sequences.Sequence<T>.firstOrNull(): T?
public inline fun <T> kotlin.sequences.Sequence<T>.firstOrNull(predicate: (T) -> kotlin.Boolean): T?
@@ -290,6 +290,14 @@ public fun kotlin.CharSequence.first(): kotlin.Char
public inline fun kotlin.CharSequence.first(predicate: (kotlin.Char) -> kotlin.Boolean): kotlin.Char
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <R : kotlin.Any> kotlin.CharSequence.firstNotNullOf(transform: (kotlin.Char) -> R?): R
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <R : kotlin.Any> kotlin.CharSequence.firstNotNullOfOrNull(transform: (kotlin.Char) -> R?): R?
public fun kotlin.CharSequence.firstOrNull(): kotlin.Char?
public inline fun kotlin.CharSequence.firstOrNull(predicate: (kotlin.Char) -> kotlin.Boolean): kotlin.Char?
@@ -2520,6 +2520,30 @@ public inline fun <T> kotlin.collections.Iterable<T>.first(predicate: (T) -> kot
public fun <T> kotlin.collections.List<T>.first(): T
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.Array<out T>.firstNotNullOf(transform: (T) -> R?): R
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.collections.Iterable<T>.firstNotNullOf(transform: (T) -> R?): R
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <K, V, R : kotlin.Any> kotlin.collections.Map<out K, V>.firstNotNullOf(transform: (kotlin.collections.Map.Entry<K, V>) -> R?): R
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.Array<out T>.firstNotNullOfOrNull(transform: (T) -> R?): R?
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.collections.Iterable<T>.firstNotNullOfOrNull(transform: (T) -> R?): R?
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <K, V, R : kotlin.Any> kotlin.collections.Map<out K, V>.firstNotNullOfOrNull(transform: (kotlin.collections.Map.Entry<K, V>) -> R?): R?
public fun <T> kotlin.Array<out T>.firstOrNull(): T?
public inline fun <T> kotlin.Array<out T>.firstOrNull(predicate: (T) -> kotlin.Boolean): T?
@@ -140,6 +140,14 @@ public fun <T> kotlin.sequences.Sequence<T>.first(): T
public inline fun <T> kotlin.sequences.Sequence<T>.first(predicate: (T) -> kotlin.Boolean): T
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.sequences.Sequence<T>.firstNotNullOf(transform: (T) -> R?): R
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : kotlin.Any> kotlin.sequences.Sequence<T>.firstNotNullOfOrNull(transform: (T) -> R?): R?
public fun <T> kotlin.sequences.Sequence<T>.firstOrNull(): T?
public inline fun <T> kotlin.sequences.Sequence<T>.firstOrNull(predicate: (T) -> kotlin.Boolean): T?
+8
View File
@@ -290,6 +290,14 @@ public fun kotlin.CharSequence.first(): kotlin.Char
public inline fun kotlin.CharSequence.first(predicate: (kotlin.Char) -> kotlin.Boolean): kotlin.Char
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <R : kotlin.Any> kotlin.CharSequence.firstNotNullOf(transform: (kotlin.Char) -> R?): R
@kotlin.SinceKotlin(version = "1.5")
@kotlin.internal.InlineOnly
public inline fun <R : kotlin.Any> kotlin.CharSequence.firstNotNullOfOrNull(transform: (kotlin.Char) -> R?): R?
public fun kotlin.CharSequence.firstOrNull(): kotlin.Char?
public inline fun kotlin.CharSequence.firstOrNull(predicate: (kotlin.Char) -> kotlin.Boolean): kotlin.Char?
@@ -1175,6 +1175,36 @@ public inline fun CharArray.first(predicate: (Char) -> Boolean): Char {
throw NoSuchElementException("Array contains no element matching the predicate.")
}
/**
* Returns the first non-null value produced by [transform] function being applied to elements of this array in iteration order,
* or throws [NoSuchElementException] if no non-null value was produced.
*
* @sample samples.collections.Collections.Transformations.firstNotNullOf
*/
@SinceKotlin("1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : Any> Array<out T>.firstNotNullOf(transform: (T) -> R?): R {
return firstNotNullOfOrNull(transform) ?: throw NoSuchElementException("No element of the array was transformed to a non-null value.")
}
/**
* Returns the first non-null value produced by [transform] function being applied to elements of this array in iteration order,
* or `null` if no non-null value was produced.
*
* @sample samples.collections.Collections.Transformations.firstNotNullOf
*/
@SinceKotlin("1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : Any> Array<out T>.firstNotNullOfOrNull(transform: (T) -> R?): R? {
for (element in this) {
val result = transform(element)
if (result != null) {
return result
}
}
return null
}
/**
* Returns the first element, or `null` if the array is empty.
*/
@@ -222,6 +222,36 @@ public inline fun <T> Iterable<T>.first(predicate: (T) -> Boolean): T {
throw NoSuchElementException("Collection contains no element matching the predicate.")
}
/**
* Returns the first non-null value produced by [transform] function being applied to elements of this collection in iteration order,
* or throws [NoSuchElementException] if no non-null value was produced.
*
* @sample samples.collections.Collections.Transformations.firstNotNullOf
*/
@SinceKotlin("1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : Any> Iterable<T>.firstNotNullOf(transform: (T) -> R?): R {
return firstNotNullOfOrNull(transform) ?: throw NoSuchElementException("No element of the collection was transformed to a non-null value.")
}
/**
* Returns the first non-null value produced by [transform] function being applied to elements of this collection in iteration order,
* or `null` if no non-null value was produced.
*
* @sample samples.collections.Collections.Transformations.firstNotNullOf
*/
@SinceKotlin("1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : Any> Iterable<T>.firstNotNullOfOrNull(transform: (T) -> R?): R? {
for (element in this) {
val result = transform(element)
if (result != null) {
return result
}
}
return null
}
/**
* Returns the first element, or `null` if the collection is empty.
*/
@@ -17,6 +17,36 @@ import kotlin.random.*
import kotlin.ranges.contains
import kotlin.ranges.reversed
/**
* Returns the first non-null value produced by [transform] function being applied to entries of this map in iteration order,
* or throws [NoSuchElementException] if no non-null value was produced.
*
* @sample samples.collections.Collections.Transformations.firstNotNullOf
*/
@SinceKotlin("1.5")
@kotlin.internal.InlineOnly
public inline fun <K, V, R : Any> Map<out K, V>.firstNotNullOf(transform: (Map.Entry<K, V>) -> R?): R {
return firstNotNullOfOrNull(transform) ?: throw NoSuchElementException("No element of the map was transformed to a non-null value.")
}
/**
* Returns the first non-null value produced by [transform] function being applied to entries of this map in iteration order,
* or `null` if no non-null value was produced.
*
* @sample samples.collections.Collections.Transformations.firstNotNullOf
*/
@SinceKotlin("1.5")
@kotlin.internal.InlineOnly
public inline fun <K, V, R : Any> Map<out K, V>.firstNotNullOfOrNull(transform: (Map.Entry<K, V>) -> R?): R? {
for (element in this) {
val result = transform(element)
if (result != null) {
return result
}
}
return null
}
/**
* Returns a [List] containing all key-value pairs.
*/
@@ -123,6 +123,40 @@ public inline fun <T> Sequence<T>.first(predicate: (T) -> Boolean): T {
throw NoSuchElementException("Sequence contains no element matching the predicate.")
}
/**
* Returns the first non-null value produced by [transform] function being applied to elements of this sequence in iteration order,
* or throws [NoSuchElementException] if no non-null value was produced.
*
* The operation is _terminal_.
*
* @sample samples.collections.Collections.Transformations.firstNotNullOf
*/
@SinceKotlin("1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : Any> Sequence<T>.firstNotNullOf(transform: (T) -> R?): R {
return firstNotNullOfOrNull(transform) ?: throw NoSuchElementException("No element of the sequence was transformed to a non-null value.")
}
/**
* Returns the first non-null value produced by [transform] function being applied to elements of this sequence in iteration order,
* or `null` if no non-null value was produced.
*
* The operation is _terminal_.
*
* @sample samples.collections.Collections.Transformations.firstNotNullOf
*/
@SinceKotlin("1.5")
@kotlin.internal.InlineOnly
public inline fun <T, R : Any> Sequence<T>.firstNotNullOfOrNull(transform: (T) -> R?): R? {
for (element in this) {
val result = transform(element)
if (result != null) {
return result
}
}
return null
}
/**
* Returns the first element, or `null` if the sequence is empty.
*
@@ -81,6 +81,36 @@ public inline fun CharSequence.first(predicate: (Char) -> Boolean): Char {
throw NoSuchElementException("Char sequence contains no character matching the predicate.")
}
/**
* Returns the first non-null value produced by [transform] function being applied to characters of this char sequence in iteration order,
* or throws [NoSuchElementException] if no non-null value was produced.
*
* @sample samples.collections.Collections.Transformations.firstNotNullOf
*/
@SinceKotlin("1.5")
@kotlin.internal.InlineOnly
public inline fun <R : Any> CharSequence.firstNotNullOf(transform: (Char) -> R?): R {
return firstNotNullOfOrNull(transform) ?: throw NoSuchElementException("No element of the char sequence was transformed to a non-null value.")
}
/**
* Returns the first non-null value produced by [transform] function being applied to characters of this char sequence in iteration order,
* or `null` if no non-null value was produced.
*
* @sample samples.collections.Collections.Transformations.firstNotNullOf
*/
@SinceKotlin("1.5")
@kotlin.internal.InlineOnly
public inline fun <R : Any> CharSequence.firstNotNullOfOrNull(transform: (Char) -> R?): R? {
for (element in this) {
val result = transform(element)
if (result != null) {
return result
}
}
return null
}
/**
* Returns the first character, or `null` if the char sequence is empty.
*/
@@ -597,6 +597,32 @@ class Collections {
assertPrints(deltas, "[3, 5, 7, 9, 11]")
}
@Sample
fun firstNotNullOf() {
data class Rectangle(val height: Int, val width: Int) {
val area: Int get() = height * width
}
val rectangles = listOf(
Rectangle(3, 4),
Rectangle(1, 8),
Rectangle(6, 3),
Rectangle(4, 3),
Rectangle(5, 7)
)
val largeArea = rectangles.firstNotNullOf { it.area.takeIf { area -> area >= 15 } }
val largeAreaOrNull = rectangles.firstNotNullOfOrNull { it.area.takeIf { area -> area >= 15 } }
assertPrints(largeArea, "18")
assertPrints(largeAreaOrNull, "18")
assertFailsWith<NoSuchElementException> { val evenLargerArea = rectangles.firstNotNullOf { it.area.takeIf { area -> area >= 50 } } }
val evenLargerAreaOrNull = rectangles.firstNotNullOfOrNull { it.area.takeIf { area -> area >= 50 } }
assertPrints(evenLargerAreaOrNull, "null")
}
}
class Aggregates {
@@ -436,6 +436,22 @@ class MapTest {
doTest("built Map", builtMap, "y", 24)
}
@Test
fun firstNotNullOf() {
val map = mapOf("Alice" to 20, "Tom" to 13, "Bob" to 18)
val firstAdult = map.firstNotNullOf { (name, age) -> name.takeIf { age >= 18 } }
val firstAdultOrNull = map.firstNotNullOfOrNull { (name, age) -> name.takeIf { age >= 18 } }
assertEquals("Alice", firstAdult)
assertEquals("Alice", firstAdultOrNull)
assertFailsWith<NoSuchElementException> { val firstChild = map.firstNotNullOf { (name, age) -> name.takeIf { age <= 11 } } }
val firstChildOrNull = map.firstNotNullOfOrNull { (name, age) -> name.takeIf { age <= 11 } }
assertNull(firstChildOrNull)
}
fun testPlusAssign(doPlusAssign: (MutableMap<String, Int>) -> Unit) {
val map = hashMapOf("a" to 1, "b" to 2)
@@ -731,6 +731,20 @@ public class SequenceTest {
assertEquals(s2, s2.orEmpty())
}
@Test
fun firstNotNullOf() {
fun Int.isMonodigit(): Boolean = toString().toHashSet().size == 1
fun Int.doubleIfNotMonodigit(): Int? = if (this > 9 && this.isMonodigit()) this * 2 else null
assertEquals(110, fibonacci().firstNotNullOf { it.doubleIfNotMonodigit() })
assertEquals(110, fibonacci().firstNotNullOfOrNull { it.doubleIfNotMonodigit() })
assertFailsWith<NoSuchElementException> {
fibonacci().take(10).firstNotNullOf<Int, Int> { it.doubleIfNotMonodigit() }
}
assertNull(fibonacci().take(10).firstNotNullOfOrNull { it.doubleIfNotMonodigit() })
}
/*
test fun pairIterator() {
val pairStr = (fibonacci() zip fibonacci().map { i -> i*2 }).joinToString(limit = 10)