ahmad
05/05/2022, 9:47 AMinput: [ "this is item number one",
"this is item number two",
"this is item number three",
"this is item number four",
"this is item number five",
"this is item number six"
]
output: [
["this is item number one", "this is item number two", "this is item number three", "this is item number four"],
["this is item number five", "this is item number six"]
]
I wrote this
private fun List<String>.batch(): List<List<String>> {
return fold(mutableListOf(mutableListOf<String>())) { accumulator, string ->
val currentBucket = accumulator.last()
val currentBucketCharsCount = currentBucket.sumOf { item -> item.length }
val willBucketExceedMaximumCharCount = currentBucketCharsCount + string.length > 100
val willBucketExceedMaximumSize = currentBucket.size + 1 > 10
if (willBucketExceedMaximumCharCount || willBucketExceedMaximumSize) {
accumulator.add(mutableListOf(string))
} else {
currentBucket.add(string)
}
accumulator
}
}
but I have a feeling that it can be done in a more cleaner/simple way. any ideas?Roukanken
05/05/2022, 10:47 AMfun List<String>.batch(): Sequence<List<String>> = sequence {
var currentBucket = mutableListOf<String>()
var currentCharCount = 0
for (item in this@batch) {
val willBucketExceedMaximumCharCount = currentCharCount + item.length > 100
val willBucketExceedMaximumSize = currentBucket.size + 1 > 10
if (willBucketExceedMaximumCharCount || willBucketExceedMaximumSize) {
yield(currentBucket)
currentBucket = mutableListOf()
currentCharCount = 0
}
currentBucket.add(item)
currentCharCount += item.length
}
if (currentBucket.isNotEmpty()) {
yield(currentBucket)
}
}
also easy optimization so you don't need to iterate the last bucket every timeahmad
05/05/2022, 11:12 AMSequence.map
doesn’t work for suspend func.
So although using sequence here made the performance better for me (3ms vs 6ms) when I do .toList
after that the runtime actually goes up to 9ms.Michael de Kaste
05/05/2022, 11:40 AMlist.asSequence().windowed(10, partialWindows = true) { window ->
window.runningFold(0) { acc, s -> acc + s.length }.indexOfFirst { it > 100 }.let {
when (it) {
-1 -> 10
in 1..10 -> it
else -> error("can't decide step size")
}
}
}
ribesg
05/05/2022, 11:43 AMFlow
instead of Sequence
if you have suspending stuff to doahmad
05/05/2022, 12:29 PMfun List<String>.batch(): Flow<List<String>> = flow {
var currentBucket = mutableListOf<String>()
var currentCharCount = 0
for (item in this@batch) {
val willBucketExceedMaximumCharCount = currentCharCount + item.length > 100
val willBucketExceedMaximumSize = currentBucket.size + 1 > 10
if (willBucketExceedMaximumCharCount || willBucketExceedMaximumSize) {
emit(currentBucket)
currentBucket = mutableListOf()
currentCharCount = 0
}
currentBucket.add(item)
currentCharCount += item.length
}
if (currentBucket.isNotEmpty()) {
emit(currentBucket)
}
}
If yes, I had this before when the batch
function was returning a List<List<String>>
val requests = request.contentsList.batch()
val responses = requests.map { batch ->
doAsyncJob(batch)
}.awaitAll()
How can I do this now after changing the batch
function to return a Flow<List<String>>
?
Sorry for the too many questions.val requests = request.contentsList.batch()
val responses = requests.map { batch ->
doAsyncJob(batch)
}.toList().awaitAll()