Introduce firstNotNullOf and firstNotNullOfOrNull #KT-12109
This commit is contained in:
@@ -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?
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1081,4 +1081,56 @@ object Elements : TemplateGroupBase() {
|
||||
}
|
||||
}
|
||||
|
||||
val f_firstNotNullOfOrNull = fn("firstNotNullOfOrNull(transform: (T) -> R?)") {
|
||||
include(Iterables, Sequences, Maps, CharSequences, ArraysOfObjects)
|
||||
} builder {
|
||||
inlineOnly()
|
||||
since("1.5")
|
||||
typeParam("R : Any")
|
||||
returns("R?")
|
||||
|
||||
sample("samples.collections.Collections.Transformations.firstNotNullOf")
|
||||
|
||||
doc {
|
||||
"""
|
||||
Returns the first non-null value produced by [transform] function being applied to ${f.element.pluralize()} of this ${f.collection} in iteration order,
|
||||
or `null` if no non-null value was produced.
|
||||
"""
|
||||
}
|
||||
body {
|
||||
"""
|
||||
for (element in this) {
|
||||
val result = transform(element)
|
||||
if (result != null) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return null
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
val f_firstNotNullOf = fn("firstNotNullOf(transform: (T) -> R?)") {
|
||||
include(Iterables, Sequences, Maps, CharSequences, ArraysOfObjects)
|
||||
} builder {
|
||||
inlineOnly()
|
||||
since("1.5")
|
||||
typeParam("R : Any")
|
||||
returns("R")
|
||||
|
||||
sample("samples.collections.Collections.Transformations.firstNotNullOf")
|
||||
|
||||
doc {
|
||||
"""
|
||||
Returns the first non-null value produced by [transform] function being applied to ${f.element.pluralize()} of this ${f.collection} in iteration order,
|
||||
or throws [NoSuchElementException] if no non-null value was produced.
|
||||
"""
|
||||
}
|
||||
body {
|
||||
"""
|
||||
return firstNotNullOfOrNull(transform) ?: throw NoSuchElementException("No element of the ${f.collection} was transformed to a non-null value.")
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user