Hello guys, is there any way to run stop mapping ...
# announcements
s
Hello guys, is there any way to run stop mapping the items when the first non null item is found? Doing that in a simple for loop would be obvious, but I would like to make use of kotlin collection operators. This question applies to the
ConfigValidator.validate
method. Any other comments or possible improvements to the code below are also welcome. Thanks!
Copy code
class ConfigValidator(private val configRules: List<Rule>) {
    abstract class Rule {
        abstract fun validateConfig(model: InitModel): RuleViolation?
    }

    fun validate(model: InitModel) = configRules.map {
        // !!! is there any way to make this stop mapping items when the first RuleViolation is found? !!!
        // this method needs to return "RuleViolation?"
        it.validateConfig(model)
    }.firstOrNull()

    class SimpleRule1(...) : Rule() {
        override fun validateConfig(model: InitModel): RuleViolation? =
            model.items.firstOrNull {
                // some condition for model item
            }?.let {
                RuleViolation(1, "Rule violation description")
            }
    }

    class SimpleRule2(...) : Rule() {
        override fun validateConfig(model: InitModel): RuleViolation? =
            model.items.firstOrNull {
                // some condition for model item
            }?.let {
                RuleViolation(2, "Rule  2 violation description")
            }
    }

    class RuleViolation(val code: Int, message: String) : Exception(message)
}
Kotlin 1.5 has
.firstNotNullOfOrNull()
, e.g.
Copy code
fun validate(model: InitModel): RuleViolation? = configRules.firstNotNullOfOrNull { it.validateConfig(model) }
1
s
Thank you very much, that is exactly what I was looking for. Unfortunately the project I am using right now uses Kotlin
v1.4.21
, but I may be allowed to update it. Thank you one more time.
Sorry for posting a large code block. I would like to edit the message to use the code snippet but I can't find the button described on the page you sent "use "Code or text snippet" available from + menu next to message input."
e
unfortunately it only works when composing the message, not when editing
😢 1
m
If you are unable to update to Kotlin 1.5, you can achieve it by using a sequence (https://kotlinlang.org/docs/sequences.html). If you run the code below you will see that the first part visits all entries in the list, while the second only visits until it gets some not-null result.
Copy code
fun main() {
    val numbers = listOf(10, 20, -10, 30, 40)
    val result = numbers
        .mapNotNull {
            println("Without sequence visiting $it")
            bogusValidation(it)
        }
        .firstOrNull()
    println("result without sequence was $result")

    val resultFromSeq = numbers
        .asSequence()
        .mapNotNull {
            println("With sequence visiting $it")
            bogusValidation(it)
        }
        .firstOrNull()
    println("result with sequence was $resultFromSeq")
}

private fun bogusValidation(i: Int) = i.takeIf { it < 0 }
e
personally I'd just write a for loop in this case,
Copy code
fun validate(model: InitModel): RuleViolation? {
    for (rule in configRules) return rule.validateConfig(model) ?: continue
    return null
}
but either option works