LastExceed
12/06/2020, 2:09 PMList<String>
that i'd like to split into a List<List<String>>
by indicating a delimiter String
, similar to how i can split a String
into a List<String>
by indicating a delimiter Char
using .split()
. unfortunately lists dont have a .split()
function, so what would be the best way to implement it ? looking for a functional approach if possibleEmmanuel REQUIER
12/06/2020, 2:19 PMstringlist.map{ it.split('char') }
Emmanuel REQUIER
12/06/2020, 2:20 PMLastExceed
12/06/2020, 2:20 PMLastExceed
12/06/2020, 2:20 PMLastExceed
12/06/2020, 2:22 PMlistOf(1,2,3,4,5).split(3) == listOf(listOf(1,2), listOf(4,5)
is what i want (and i just realized it doesnt need to be strings, any type works)Emmanuel REQUIER
12/06/2020, 2:22 PMEdgars
12/06/2020, 2:22 PMselector
returns true
, that string is considered the delimiter.Edgars
12/06/2020, 2:27 PMfun <T> List<T>.chunkedBy(selector: (T) -> Boolean): List<List<T>> {
val chunks = mutableListOf(mutableListOf<T>())
val chunk = mutableListOf<T>()
for (item in this) {
if (selector(item)) {
chunks.add(chunk)
chunk.clear()
} else {
chunk.add(item)
}
}
chunks.add(chunk) // add the last chunk that wasn't separated
return chunks
}
Or something like that. But I'm not sure what would happen if you had multiple delimeters at the end, for example. Not sure what my code would do either, to be honest. Add multiple empty lists? Could add filter { it.isNotEmpty() }
.LastExceed
12/06/2020, 2:29 PMNir
12/06/2020, 4:11 PMNir
12/06/2020, 4:12 PMNir
12/06/2020, 4:12 PMNir
12/06/2020, 4:16 PMVadim
12/07/2020, 12:49 AMfun <T> List<T>.split(separator: T): List<List<T>> = fold(emptyList()) { acc, element ->
when {
element == separator -> acc.plusElement(emptyList())
acc.isNotEmpty() -> acc.dropLast(1).plusElement(acc.last().plusElement(element))
else -> listOf(listOf(element))
}
}
Scott Christopher
12/07/2020, 1:02 AMfun <A> List<A>.splitWhen(f: (A) -> Boolean): List<List<A>> =
if (isEmpty()) emptyList()
else listOf(takeWhile { !f(it) }) + dropWhile { !f(it) }.drop(1).splitWhen(f)
listOf(1, 2, 3, 4, 5).splitWhen { it == 3 }
You'll need to think about how you want to handle neighbouring separators though, e.g.
listOf(1, 2, 3, 3, 4, 5).splitWhen { it == 3 }
Do you want that to evaluate to listOf(listOf(1, 2), emptyList(), listOf(4, 5))
or listOf(listOf(1, 2), listOf(4, 5))
?Nir
12/07/2020, 1:57 AMNir
12/07/2020, 1:58 AMScott Christopher
12/07/2020, 1:58 AMScott Christopher
12/07/2020, 1:59 AMfun <A> List<A>.splitWhen(f: (A) -> Boolean): List<List<A>> {
tailrec fun go(rest: List<A>, result: List<List<A>>): List<List<A>> =
if (rest.isEmpty()) result
else go(
rest.dropWhile { !f(it) }.drop(1),
result + listOf(rest.takeWhile { !f(it) })
)
return go(this, emptyList())
}
Nir
12/07/2020, 4:53 AMNir
12/07/2020, 4:55 AMNir
12/07/2020, 5:28 PMNir
12/07/2020, 5:28 PMfun Sequence<String>.chunkedByEmpty(): Sequence<List<String>> = sequence {
var currentList = mutableListOf<String>()
for (x in this@chunkedByEmpty) {
if (x != "") {
currentList.add(x)
continue
}
yield(currentList)
currentList = mutableListOf<String>()
}
yield(currentList)
}
inline fun <R> File.useChunkedLines(transform: (Sequence<List<String>>) -> R) =
useLines { transform(it.chunkedByEmpty()) }