I have a list of strings that I want to split into...
# stdlib
s
I have a list of strings that I want to split into sublists, where the delimiter is a predicate lambda (string matches a certain property). How can I do this?
j
partition or groupBy and then values
e
that doesn't exactly work (without hacks) if what Sam wants is contiguous sublists
the hack could be something like this fwiw
Copy code
fun <T> Iterable<T>.splitWhen(predicate: (T) -> Boolean): List<List<T>> {
    var counter = 0
    return groupBy { if (predicate(it)) ++counter else counter }.values.map { it.dropWhile(predicate) }
}

listOf(1, 2, 0, 3, 0, 0, 4).splitWhen { it == 0 } // [[1, 2], [3], [], [4]]
s
Seems O(N^3) or so. Adapted this from SO (~O(N^2)):
Copy code
fun <E> List<E>.split(includeDelimiter: Boolean = false, predicate: (E) -> Boolean): List<List<E>> {
        return flatMapIndexed { index, x ->
                when {
                    index == 0 || index == lastIndex -> listOf(index)
                    predicate(x) -> listOf(index - 1, index + 1)
                    else -> emptyList()
                }
            }
            .windowed(size = 2, step = 2) { (from, to) -> slice( (if(includeDelimiter) (from - 1).coerceAtLeast(0) else from)..to) }
    }
e
what makes you think it's O(N^3)/O(N^2)? they're both O(N)
😁 1
if you care about minimizing garbage then you should choose something like
Copy code
fun <E> Iterable<E>.split(predicate: (E) -> Boolean): List<List<E>> = buildList {
    val last = this@split.fold(mutableListOf<E>()) { acc, elem ->
        if (predicate(elem)) {
            add(acc.orEmpty())
            mutableListOf()
        } else {
            acc.add(elem)
            acc
        }
    }
    if (last.isNotEmpty()) add(last)
}
over either of the above
s
3 loops:
groupBy
,
map
,
dropWhile
.
e
so?
groupBy
iterates
N
elements once.
map
iterates the groups and
dropWhile
iterates over at most 1 element of each group, and even if it iterated the whole group, it would still sum to at most
N
total.
2