What would be the functional equivalent of this? I...
# announcements
f
What would be the functional equivalent of this? I frown upon these MutableList things (the old java way) nowadays and always
map
stuff instead but I can’t figure out how to do this. I’m essentially looping over a sequence and I want to place things into three different lists, like
partition
but for three output collections instead of two. Is there some general function or a combination that can do this?
Copy code
val success: MutableList<String> = ArrayList()
val failed: MutableList<String> = ArrayList()
val ignored: MutableList<String> = ArrayList()

for (string in strings) {
    val result = doStuff(string)
    when {
        result != null -> success.add(ingredient)
        other condition -> ignored.add(string)
        else -> failed.add(string)
    }
}
j
use partition twice? first partition into success / rest, then partition rest into ignored / failed?
r
Copy code
strings.groupBy {
    val result = duStuff(string)
    when {
        result != null -> "success"
        other condition -> "ignored"
        else -> "failed"
    }
}
would give a
Map<String, List<String>>
with the three keys (
success
,
ignored
,
failed
).
k
Better make a quick enum for that!
Even a
Boolean?
would be safer 🧌
s
Copy code
fun main() {
    val strings = listOf("a", "b", "c")

    print(strings.groupBy { doStuff(it) })
}

sealed class StringResult {
    object Success: StringResult()
    object Ignored: StringResult()
    object Failed: StringResult()
}

fun doStuff(string: String): StringResult =
    when(string) {
        "a" -> StringResult.Success
        "b" -> StringResult.Ignored
        else -> StringResult.Failed
    }
prints out
Copy code
{StringResult$Success@7e0babb1=[a], StringResult$Ignored@5ba23b66=[b], StringResult$Failed@c818063=[c]}
k
That's literally an enum...
s
yeah, agreed
If you ever had to encode status messages or results inside the result of doStuff, having a sealed class is useful
you’d just convert the
object
cases to
data class
and give them fields to fill in with
doStuff()
But for this example, an enum is enough
f
Awesome replies! Thanks alot, totally forgot about
groupBy
, I have lists now but I can just as easily use a hash. Will read up on sealed classes as well 🙂
d
For this example, a string as key is enough - the implementation should never leak
How about this for the general case?
Copy code
fun <T> Iterable<T>.partitioned(vararg predicates: (T) -> Boolean): List<List<T>> =
    predicates.map { groupBy { predicates.asIterable().firstMatch(it) }.getOrDefault(it, emptyList())}

private fun <T> Iterable<(T) -> Boolean>.firstMatch(item: T): ((T) -> Boolean)? = this.find { it(item) }