What would be the most ideomatic way to do such a ...
# getting-started
d
What would be the most ideomatic way to do such a thing in Kotlin?
Copy code
val l = listOf(foo1, foo2, foo3)

var found = l.find(::criteria1)

if (found != null) return doAction(found)

var found = l.find(::criteria2)

if (found != null) return doAction2(found)

...
t
Copy code
fun test(): T? {
    fun criteria1(item: Int): Boolean = item == 3
    fun criteria2(item: Int): Boolean = item == 1
    
    val criterias = listOf(::criteria1, ::criteria2)
    val list = listOf(1, 2, 3)
    
    for (criteria in criterias) {
        list.find(criteria)?.let { return doAction(it) }
    }
    
    return null
}
Something like this?
d
Nope, there's different doActions for each criteria... and some criteria need additional checks on the found foo to decide which action...
w
🤔 good one, didn’t test this, but here is my suggestion, something in these lines:
Copy code
fun asas(): Int {
        fun criteria1(item: Int): Boolean = item == 3
        fun criteria2(item: Int): Boolean = item == 1
        fun doAction(item: Int): Int = item
        fun doAction2(item: Int): Int = item

        val list = listOf(1, 2, 3)

        val actionsForCriteria: Map<(Int) -> Boolean, (Int) -> Int> = mapOf(
            ::criteria1 to ::doAction,
            ::criteria2 to ::doAction2,
        )

        return actionsForCriteria.firstNotNullOfOrNull { (criteria, action) ->
            list.firstOrNull(criteria)?.let(action)
        } ?: error("Not found!")
    }
👍 1
t
Copy code
typealias Criteria = (Int) -> Boolean
typealias SubCriteria = (Int) -> Boolean
typealias Action = (Int) -> String

fun test(): String? {  
    val criteriaMap: Map<Criteria, Map<SubCriteria, Action>> = mapOf(
        { item: Int -> item == 3 } to mapOf(
            { item: Int -> item % 2 == 0 } to { item: Int -> item.toString() }
        )
    )
    
    val list = listOf(1, 2, 3)

    for ((criteria, subCriteriaMap) in criteriaMap) {
        list.find(criteria)?.let { found ->
            for ((subCriteria, action) in subCriteriaMap) {
                if (subCriteria(found)) {
                    return action(found)
                }
            }
        }
    }
    
    return null
}
But it does get rather big...
d
In the end, if there would be only one level of criteria per action, your suggestions would probably be nice 😉... in my case, I guess the more readable solution would be:
Copy code
l.find(::criteria1)?.let { return doAction1(it) }

l.find(::criterai2)?.let { return if (it.subcriteria()) doAction2_1(it) else doAction2_2(it) }
👍 1
Thanks for the responses 🙂!