Reputation: 63
I'd like to return the first non-null value after the transformation of a list of elements in Kotlin, so something like this:
suspend fun myFunction(): Any {
val firstNonNullId = this.mapNotNull{ it.id }
?.first{ transform(id) != null }
return transform(firstNonNullID)
}
What would be a better and more idiomatic way to write this function? I'd like to call upon transform(it)
as few times as possible, and the transformation in question is also a suspend
function.
Edit: The asSequence()
solution gives an error when the transform()
is a suspend
function, as it must be called from a coroutine body. This happens even if the overall myFunction()
is a suspend function. What should the solution be when the transformation is a suspend function?
Upvotes: 5
Views: 3845
Reputation: 23115
Since Kotlin 1.5, you can use firstNotNullOf
function or its ...OrNull
variant:
// returns the first non-null result of transform
this.firstNotNullOf { transform(it.id) }
firstNotNullOf
throws an exception if no non-null result of the transformation is found, and firstNotNullOfOrNull
returns null in this situation.
Both functions are inline, so it should be possible to call suspend functions in their lambda parameters when they are themselves invoked from a suspend function.
Upvotes: 8
Reputation: 5002
I would suggest to use Kotlin sequences:
this.asSequence()
.mapNotNull { it.id }
.mapNotNull { transform(it) }
.first()
Since sequence evaluation is lazy, your transform function will only be called during the call to .first()
, and it will not be called after the first non-null result is obtained.
Upvotes: 2