Hey folks. I have a sequence and I want to create ...
# getting-started
g
Hey folks. I have a sequence and I want to create a function to group the elements in that sequence on the fly (i.e., without waiting until the last element on the original sequence). Can I do that with a purely functional approach? I can get it to work with
sequence {}
but it feels like an overkill to use a couroutine for this. Consider the code below:
Copy code
data class MessageWithExpiry(
    val messageSerialized: ByteArray,
    val expiryDate: ZonedDateTime
)

data class Batch(
    val messages: Array<ByteArray>,
    val latestMessageExpiryDate: ZonedDateTime
)

fun batchMessages(messages: Sequence<MessageWithExpiry>): Sequence<Batch> = TODO()
Each
Batch
should contain an array of messages (taken from
MessageWithExpiry.messageSerialized
) which collectively don't exceed 8 MiB. If
messages
is empty, the result should be empty too. If all the
messages
fit in one batch (i.e., they don't exceed the 8 MiB limit collectively), then only one batch should be output -- otherwise, multiple `Batch`es should be output. Additionally, each batch should have the latest expiry date of any message in the batch. Intuitively, I think I should split this in two parts: One for the batching itself (using something like
Sequence.scan
but not that per se), and another for the computation of each
Batch.latestMessageExpiryDate
(using
Sequence.map
). But I don't think
Sequence.scan
,
Sequence.reduce
,
Sequence.fold
or any of their variations would help me do the first part. Any pointers on whether/how I can do this using a functional approach?
t
So if I understood correctly, you don't want to group by a certain property, but you just want to build batches of multiple messages (up to a certain size). The only way I see to achieve this is implementing a custom Sequence that combines multiple elements of the original sequence into one when the next element is fetched.
g
So if I understood correctly, you don't want to group by a certain property, but you just want to build batches of multiple messages (up to a certain size).
That's right
The only way I see to achieve this is implementing a custom Sequence that combines multiple elements of the original sequence into one when the next element is fetched.
Sorry, what do you mean by custom sequence? Using
sequence {}
and `yield`ing the values?
t
that's one way to do it - and actually that way uses coroutines.
Sequence
in kotlin is actually just an interface that requires you to provide an interator. You can implement it as a class without any predefined kotlin functions. But that's rarely necessary.
g
I see! I didn't realise I could just implement that interface. Thanks Tobias!
t
just for fun I wrote a possible implementation down (using
sequence{}
and
yield
). I have not tested this at all but it looks like it should work https://gist.github.com/tobiberger/178f436d23fa40f388f4c891921cf0f7
g
LGTM. Thank you so much!