https://kotlinlang.org logo
#announcements
Title
# announcements
б

Бежан Александр

06/21/2019, 11:37 AM
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

murphy

06/21/2019, 11:49 AM
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

U75957

06/21/2019, 11:52 AM
You can write your own extension function
collectFirst
m

murphy

06/21/2019, 11:52 AM
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

bezrukov

06/21/2019, 11:53 AM
You can try to play with a sequence to avoid intermediate result, something like that:
list.asSequence().filter { }.map {  }.first()
m

murphy

06/21/2019, 11:59 AM
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

Pavlo Liapota

06/21/2019, 12:05 PM
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

murphy

06/21/2019, 12:07 PM
@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.
б

Бежан Александр

06/21/2019, 12:29 PM
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

Pavlo Liapota

06/21/2019, 12:47 PM
@murphy Ah, I see, sorry, I am not familiar with Scala 🙂 @Бежан Александр You can also make that extension function
inline
.
m

murphy

06/21/2019, 12:49 PM
The solution using
asSequence
before
mapNotNull
and
firstOrNull
instead of a dedicated extension method would also avoid computing too many intermediate results.
б

Бежан Александр

06/21/2019, 12:50 PM
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

murphy

06/21/2019, 12:52 PM
Sure, if this functionality is used frequently an extension function definitely makes sense.
б

Бежан Александр

06/21/2019, 12:52 PM
@Pavlo Liapota thanks for inline suggestion
@murphy Yeah, exactly
6 Views