Lukasz Kalnik
01/31/2023, 8:47 PMgenerateSequence { /*...*/ }.forEach { _ -> }
ephemient
01/31/2023, 8:53 PM.count()
Casey Brooks
01/31/2023, 8:53 PMI only use some side effects which happened during sequence computationDo you even need a sequence at all, then? It seems like you should either apply those side effects during a
.forEach
block rather than in the generator, or else drop the sequence altogether and just run a normal loopephemient
01/31/2023, 8:54 PM.onEach {}
, then just do those in .forEach {}
insteadLukasz Kalnik
02/01/2023, 8:03 AMephemient
02/01/2023, 8:13 AM.indexOfFirst { }
to find the index instead of using an external variable?Lukasz Kalnik
02/01/2023, 8:16 AMIterable
.ephemient
02/01/2023, 8:17 AM.indexOfFirst
is available on Sequence, .windowed
shouldn't keep anything more in memory than necessaryLukasz Kalnik
02/01/2023, 8:22 AMval windowSize = 4
val result = message.asSequence()
.windowed(windowSize)
.map { chunk -> chunk.toSet().size == windowSize }
.indexOfFirst { found -> found }
CLOVIS
02/01/2023, 9:03 AMcollect
and the lambda is optional—but that's not really an expected pattern with sequences)Lukasz Kalnik
02/01/2023, 9:15 AMCLOVIS
02/01/2023, 2:28 PMsomeFlow()
// …
.onEach { … }
// …
.collect()
Lukasz Kalnik
02/01/2023, 2:31 PMephemient
02/01/2023, 2:48 PM.map { ... }.indexOfFirst { it }
, just .indexOfFirst { ... }
Casey Brooks
02/01/2023, 4:16 PMsuspend
mechanism of coroutines, but are not normal `kotlinx.coroutines`; you cannot do things like launch { }
within a sequence scope, and the whole Sequence pipeline runs synchronously. It basically does the same job as for(x in y)
, but with a different syntax that allows for more fluent and readable processing of the elements in y
.
Furthermore, converting something that’s already in memory to a Sequence doesn’t automatically make it more efficient. You’d need the source itself to emit values lazily in a sequence { }
or generateSequence { }
block to actually process a large data set lazily with a roughly-constant amount of memory. In your case, a String is already fully in-memory, so windowing it and processing it as a Sequence wouldn’t really make it process more efficiently than a normal for
loop if it’s really large, since the whole String is already loaded into memory. What you’d need to do is read the “window” from the source file, rather than reading a line into memory and windowing that.
And there’s a difference between the use-case of sequence { }
or generateSequence { }
. generateSequence { }
is more for generating a “mathematical” sequence, where each element is strictly a function of the one before it (generateSequence(7) { it + 2 }
produces [7, 9, 11, …]
). It basically handles the iteration internally, and you just provide a function to derive one value from the previous one. If you’re looking to do more standard iteration, then sequence { }
is the one you should be using instead, which lets you directly yield values to the sequence from within the block using whatever iteration logic you need. But in both cases, all the logic needed should be contained within the sequence’s lambda, not modifying values from outside it. As Ivan mentioned, they should be pure functions in the Functional Programming sense.CLOVIS
02/01/2023, 4:20 PM.onComplete
on Sequence. It's important because it means a Sequence cannot free resources when it's done, flows can. E.g. when using #kmongo, iterating over a request with a Sequence forces the entire request to be loaded in memory so the cursor can be closed. Meanwhile, iterating with a flow is truly lazy (only the requested values are read, and the cursor is closed when a terminal operation finishes)Lukasz Kalnik
02/01/2023, 7:05 PMfor
loop here, because I wanted to solve the task in a more declarative/functional way. And I wanted to learn something about sequences. And thanks to all of you helpful people, I learned even more than I anticipated. 🙂 Thank you again for being so helpful.String.windowedSequence()
which is again one less call in my solution 🙂ephemient
02/01/2023, 8:08 PMfun <T> Iterable<T>.allDistinct(): Boolean = all(mutableSetOf<T>()::add)
fun CharSequence.allDistinct(): Boolean = all(mutableSetOf<Char>()::add)
etc. instead of checking .size
, but that's sorta beside the point here)Lukasz Kalnik
02/02/2023, 7:46 AMO(n)
instead of O(nlogn)
when just converting to a HashSet).ephemient
02/02/2023, 9:43 PM.toSet()
is O(n), where's the O(nlogn) from?
I just brought it up as it can stop as soon as it finds a single duplicate and doesn't require knowing the size (e.g. it works on Iterable
)