Read on for an introduction to the most important functions for single element access: find
, first
, last
, indexOf
, lastIndexOf
, single
, and their variants.
Single-element access
find
//sampleStart inline fun <T> Iterable<T>.find(predicate: (T) -> Boolean): T? //sampleEnd
The find
function searches for the first element satisfying a predicate and returns it. If no such element is found, it returns null
.
Example
//sampleStart fun main() { val list = listOf(1, 2, 3, 4, 5) list.find { it > 3 }.also(::println) // 4 list.find { it < 0 }.also(::println) // null } //sampleEnd
There is also the findLast
variant, which returns the last element satisfying a predicate, or null
.
//sampleStart inline fun <T> Iterable<T>.findLast(predicate: (T) -> Boolean): T? //sampleEnd
Example
//sampleStart fun main() { val list = listOf(1, 2, 3, 4, 5) list.findLast { it > 3 }.also(::println) // 5 list.findLast { it < 3 }.also(::println) // 2 } //sampleEnd
first
, last
//sampleStart fun <T> List<T>.first(): T fun <T> List<T>.last(): T //sampleEnd
The first
/last
functions return, as you would expect, the first/last elements of a list. When the list is empty, they throw a NoSuchElementException
.
Example
//sampleStart fun main() { val list = listOf(1, 2, 3, 4, 5) list.first().also(::println) // 1 list.last().also(::println) // 5 } //sampleEnd
There are a couple of useful variants.
One variant accepts a predicate, and returns the first/last element satisfying that predicate, or throws NoSuchElementException
if no such element is found.
//sampleStart inline fun <T> Iterable<T>.first(predicate: (T) -> Boolean): T inline fun <T> Iterable<T>.last(predicate: (T) -> Boolean): T //sampleEnd
Example:
//sampleStart fun main() { val list = listOf(1, 2, 3, 4, 5) list.first { it % 2 == 0 }.also(::println) // 2 list.last { it % 2 == 0 }.also(::println) // 4 } //sampleEnd
The *OrNull
variants return null
instead of throwing when run on an empty list.
//sampleStart fun <T> List<T>.firstOrNull(): T? fun <T> List<T>.lastOrNull(): T? inline fun <T> Iterable<T>.firstOrNull(predicate: (T) -> Boolean): T inline fun <T> Iterable<T>.lastOrNull(predicate: (T) -> Boolean): T //sampleEnd
Finally, firstNotNullOf
and firstNotNullOfOrNull
apply a transformation to each element, and return the first result which is not null. The former throws NoSuchElementException
if no such element is found, while the latter returns null
.
//sampleStart inline fun <T, R : Any> Iterable<T>.firstNotNullOf( transform: (T) -> R? ): R inline fun <T, R : Any> Iterable<T>.firstNotNullOfOrNull( transform: (T) -> R? ): R? //sampleEnd
Example
//sampleStart interface Entity { val id: Long } interface EntityRepository { fun retrieve(id: Long): Entity? fun firstExisting(ids: List<Long>): Entity? = ids.firstNotNullOfOrNull { retrieve(it) } } //sampleEnd fun main() { val poem = """ In the code's carnival, Kotlin's the delight, With extension functions, it takes flight. From loops to spins, a coding spree, In the world of development, it's the key! """.trimIndent() println(poem) }
indexOf
, lastIndexOf
//sampleStart fun <T> Iterable<T>.indexOf(element: T): Int fun <T> Iterable<T>.lastIndexOf(element: T): Int //sampleEnd
Returns the index of the first/last occurrence of element
, or -1
if no such element is found.
//sampleStart fun main() { val list = listOf(1, 2, 3, 2, 5) list.indexOf(2).also(::println) // 1 list.lastIndexOf(2).also(::println) // 3 } //sampleEnd
The related indexOfFirst
/indexOfLast
methods accepts a predicate and return the index of the first/last element that satisfies it.
//sampleStart inline fun <T> Iterable<T>.indexOfFirst( predicate: (T) -> Boolean ): Int inline fun <T> Iterable<T>.indexOfLast( predicate: (T) -> Boolean ): Int //sampleEnd
Example
//sampleStart fun main() { val list = listOf(1, 2, 3, 4, 5) list.indexOfFirst { it % 2 == 0 }.also(::println) // 1 list.indexOfLast { it % 2 == 0 }.also(::println) // 3 } //sampleEnd
single
//sampleStart fun <T> Iterable<T>.single(): T //sampleEnd
An interesting function that returns the single element of a list if it only contains a single element, and throws otherwise.
Example
//sampleStart fun main() { // listOf().single() // throws NoSuchElementException listOf(1).single().also(::println) // 1 // listOf(1, 2).single() // throws IllegalArgumentException } //sampleEnd
There are a few variations:
One variation accepts a predicate, and returns the element satisfying it if there is precisely one, and throws otherwise.
//sampleStart fun <T> Iterable<T>.single(predicate: (T) -> Boolean): T //sampleEnd
Example
//sampleStart fun main() { val list = listOf(1, 2, 3) // list.single { it > 3 } // throws NoSuchElementException list.single { it > 2 }.also(::println) // 3 // list.single { it > 1 } // throws IllegalArgumentException } //sampleEnd
There are also *OrNull
variants for both of the above, which return null
instead of throwing.
//sampleStart fun <T> Iterable<T>.singleOrNull(): T? fun <T> Iterable<T>.singleOrNull(predicate: (T) -> Boolean): T? //sampleEnd