Problems with flatMap function on ReceiveChannel<T>
See original GitHub issueThe ReceiveChannel<E>.flatMap
function currently works like this:
- take the 1st
ReceiveChannel<R>
fromtransform
function and pipe all values from it to theflatMap
result channel, - take the 2nd
ReceiveChannel<R>
fromtransform
function and pipe all values from it to theflatMap
result channel, 3 … n …
This way the following test:
val channel = produce {
send("1000")
send("1")
}
val list = channel.flatMap { value ->
produce {
delay(value.toLong())
send(value)
}
}.toList()
assertEquals(listOf("1", "1000"), list)
fails. That is if a value from the 2nd ReceiveChannel<R>
comes earlier than the value from the 1st ReceiveChannel<R>
it still is processed after the value from the 1st ReceiveChannel<R>
.
I think it should work on a first-come-first-go basis.
A preliminary version of my version of flatMap
is sth like this:
private fun <E, R> ReceiveChannel<E>.flatMap(context: CoroutineContext = Unconfined,
transform: suspend (E) -> ReceiveChannel<R>): ReceiveChannel<R> =
produce(context) {
val transformed = mutableListOf<ReceiveChannel<R>>()
val deferredList = mutableListOf<Deferred<ReceiveChannel<R>>>()
var finishedSource = false
while (isActive &&
(!finishedSource || transformed.isNotEmpty() || deferredList.isNotEmpty())) {
selectUnbiased<Unit> {
this@flatMap.onReceiveOrNull { value ->
when {
value != null -> deferredList += async(context) { transform(value) }
else -> finishedSource = true
}
}
transformed.forEach { output ->
output.onReceiveOrNull { value ->
when {
value != null -> this@produce.send(value!!)
else -> transformed -= output
}
}
}
deferredList.forEach { deferred ->
deferred.onAwait { output ->
deferredList -= deferred
transformed += output
}
}
}
}
}
It might not work correctly all the times (e.g. I haven’t done any analysis on cancelling behaviour), but it should give you an idea of how I imagine it.
Issue Analytics
- State:
- Created 6 years ago
- Comments:6 (5 by maintainers)
Top Results From Across the Web
Array.prototype.flatMap() - JavaScript - MDN Web Docs
The flatMap() method returns a new array formed by applying a given callback function to each element of the array, and then flattening...
Read more >Scala | flatMap Method - GeeksforGeeks
Here, flatMap is applied on the another function defined in the program and so a list of sequence of numbers is generated.
Read more >Java 8 Streams FlatMap method example - Stack Overflow
The Function passed to flatMap is responsible for creating the Stream , so the example I give is really shorthand for integerListStream .flatMap(ints...
Read more >PySpark flatMap() Transformation - Spark by {Examples}
PySpark flatMap() is a transformation operation that flattens the RDD/DataFrame (array/map DataFrame columns) after applying the function on every element.
Read more >Project Reactor: map() vs flatMap() - Baeldung
Now, let's see how we can use the map operator. The Flux#map method expects a single Function parameter, which can be as simple...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Thanks. Indeed, a sequential
flatMap
is not that useful for asynchronous channels. My suggestion to solve this problem is this:flatMap
name for synchronous cases, e.g. when transform returns either aCollection
or aSequence
(implement the corresponding versions)flatMap
withReceiveChannel
transforms to avoid any confusion and consider reintroducing it under the name ofconcatMap
. For the sake of consistency,concat
operation on two channels should be introduced, too.mergeMap
that would process all items on first-come-first-served basis. The correspondingmerge
operator for two channels would also help.switchMap
that would take items from the first channel only only the next channel is received (switch to it), etc. The correspondingswitch
operator for two channels might also be helpful.Closing as obsolete,
flatMap
on the channel is deprecated