Giszmo
Giszmo

Reputation: 2127

How can I find the first element's method result that is not null?

So I have parsers and want to use the first that does return a non-null value. How would I do that most elegantly?

return parsers.map { it.parse(content) }.firstOrNull { it != null }

would map all (million?) parsers before picking the first.

return parsers.firstOrNull { it.parse(content) != null }?.parse(content)

would run the (expensive?) parse() once again.

I know I can

for (parser in parsers) {
    val result = parser.parse(content)
    if (result != null) {
        return result
    }
}
return null
parsers.forEach { it.parse(content)?.run { return this } }
return null

is the shortest I can get but it's not nice to read.

I'm pretty sure there is a shortcut here that I don't see.

Upvotes: 0

Views: 666

Answers (3)

gromyk
gromyk

Reputation: 610

Also, you can use the following code:

parsers.asSequence()
    .mapNotNull { it.parse(content) }
    .first()

Upvotes: 3

gidds
gidds

Reputation: 18557

As an alternative to the overhead of a Sequence, or mapping lots of values unnecessarily, you could use an extension method such as:

inline fun <T, R> List<T>.firstMappedNotNull(transform: (T) -> R): R? {
    for (e in this)
        return transform(e) ?: continue
    return null
}

This uses the minimum of mapping function calls and temporary objects.  It's necessarily written in an imperative way, but it's quite short, and makes your own code short, clear, and functional.

(This version returns null if the list was empty or every mapping returned null.  You could of course change the signature and last line to throw an exception instead.)

It's a shame this function isn't already in the standard library.  But it's easy to add your own!

Upvotes: 4

marstran
marstran

Reputation: 27971

Use a sequence. It makes your computation lazy, so that you will only compute parse as many times as you need.

return parsers.asSequence()
              .map { it.parse(content) }
              .find { it != null }

Upvotes: 6

Related Questions