Hey guys. I want a combination of find and map in ...
# announcements
б
Hey guys. I want a combination of find and map in a single function. Find a first element that satisfies a predicate and map it over function at the same time. Scala has
collectFirst
for that. How to do it in Kotlin ?
m
You could use
mapNotNull
with your partial transformation function and then
firstOrNull
on the result.
However, that computes the full intermediate result.
You could also use
firstOrNull
with a predicate and then transform the result, if any.
u
You can write your own extension function
collectFirst
m
If you only have a partial function, no associated predicate and you want to evaluate this lazily, then I think you'll have to write your own method.
b
You can try to play with a sequence to avoid intermediate result, something like that:
list.asSequence().filter { }.map {  }.first()
m
The generic implementation of
collectFirst
is also not hard to write, for example like this:
Copy code
fun <T, R> Iterable<T>.collectFirst(transform: (T) -> R?) : R? {
    for (i in this) {
        val o = transform(i)
        if (o != null) return o
    }
    return null
}
p
Or for example:
Copy code
list
    .find { it % 2 == 0 }
    ?.let { abs(it) }
If you need separate lambdas for predicate and transformation, then one function call will not look nice:
Copy code
list.collectFirst({ it % 2 == 0 }, { abs(it) })
m
@Pavlo Liapota I would also recommend to split the function into predicate and transformation, because that will be more clear and will allow the use of existing library functions. But the OP specifically asked for an analogon of a Scala library method and that method only takes one partial function as its argument, so I replicated that behaviour.
б
Thank you guys. I think @murphy version is exactly what I’m looking for. The thing is that I don’t wanna recompute value, since filtering function already does the mapping, I just want this result.
p
@murphy Ah, I see, sorry, I am not familiar with Scala 🙂 @Бежан Александр You can also make that extension function
inline
.
m
The solution using
asSequence
before
mapNotNull
and
firstOrNull
instead of a dedicated extension method would also avoid computing too many intermediate results.
б
Yeah, this is also good
I would create
collectFirst
extension function in anyway. Since I want this level of abstraction and don’t wanna know how it’s implemented.
m
Sure, if this functionality is used frequently an extension function definitely makes sense.
б
@Pavlo Liapota thanks for inline suggestion
@murphy Yeah, exactly