Kotlin协程压缩三个流
有一个函数可以压缩两个Kotlin协程压缩三个流,kotlin,kotlin-coroutines,kotlin-coroutines-flow,Kotlin,Kotlin Coroutines,Kotlin Coroutines Flow,有一个函数可以压缩两个流。是否有什么东西可以将三个(或更多)的流压缩在一起 如果没有,你能帮我实现它的扩展功能吗?比如: flow.zip(flow2, flow3) { a, b, c -> } 我还没有测试过这个,但是你可以试试。zip有很多底层代码,因此为了利用这些代码,我将前两个流压缩为一个对流,然后将对流压缩为第三个流。但是传递给这个函数的lambda得到了前两个已经分离的lambda,因此它不必知道中间对步骤 fun <T1, T2, T3, R> zip(
流
。是否有什么东西可以将三个(或更多)的流压缩在一起
如果没有,你能帮我实现它的扩展功能吗?比如:
flow.zip(flow2, flow3) { a, b, c ->
}
我还没有测试过这个,但是你可以试试。zip
有很多底层代码,因此为了利用这些代码,我将前两个流压缩为一个对流,然后将对流压缩为第三个流。但是传递给这个函数的lambda得到了前两个已经分离的lambda,因此它不必知道中间对步骤
fun <T1, T2, T3, R> zip(
first: Flow<T1>,
second: Flow<T2>,
third: Flow<T3>,
transform: suspend (T1, T2, T3) -> R
): Flow<R> =
first.zip(second) { a, b -> a to b }
.zip(third) { (a, b), c ->
transform(a, b, c)
}
对于任意数量的流,这里有一个未经测试的版本,但它们必须是相同的类型:
fun <T, R> zip(
vararg flows: Flow<T>,
transform: suspend (List<T>) -> R
): Flow<R> = when(flows.size) {
0 -> error("No flows")
1 -> flows[0].map{ transform(listOf(it)) }
2 -> flows[0].zip(flows[1]) { a, b -> transform(listOf(a, b)) }
else -> {
var accFlow: Flow<List<T>> = flows[0].zip(flows[1]) { a, b -> listOf(a, b) }
for (i in 2 until flows.size) {
accFlow = accFlow.zip(flows[i]) { list, it ->
list + it
}
}
accFlow.map(transform)
}
}
fun-zip(
vararg流:流,
转换:挂起(列表)->R
):Flow=when(flows.size){
0->错误(“无流”)
1->流[0]。映射{transform(listOf(it))}
2->flows[0].zip(flows[1]){a,b->transform(listOf(a,b))}
其他->{
var accFlow:Flow=flows[0].zip(flows[1]){a,b->listOf(a,b)}
用于(i/2,直到流量大小){
accFlow=accFlow.zip(flows[i]){list,it->
列表+它
}
}
accFlow.map(转换)
}
}
您可以检查zip
运营商的实施情况,并尝试复制/模拟它的工作方式,使其适应您的需要
测试它并进行所有需要的更改
fun <T1, T2, T3, R> Flow<T1>.zip(flow2: Flow<T2>, flow3: Flow<T3>, transform: suspend (T1, T2, T3) -> R): Flow<R> = channelFlow {
val first: ReceiveChannel<T1> = produce {
this@zip.collect {
channel.send(it)
}
}
val second: ReceiveChannel<T2> = produce {
flow2.collect {
channel.send(it)
}
}
val third: ReceiveChannel<T3> = produce {
flow3.collect {
channel.send(it)
}
}
(second as SendChannel<*>).invokeOnClose {
if (!first.isClosedForReceive) first.cancel(MyFlowException())
if (!third.isClosedForReceive) third.cancel(MyFlowException())
}
(third as SendChannel<*>).invokeOnClose {
if (!first.isClosedForReceive) first.cancel(MyFlowException())
if (!second.isClosedForReceive) second.cancel(MyFlowException())
}
val otherIterator = second.iterator()
val anotherIterator = third.iterator()
try {
first.consumeEach { value ->
if (!otherIterator.hasNext() || !anotherIterator.hasNext()) {
return@consumeEach
}
send(transform(value, otherIterator.next(), anotherIterator.next()))
}
} catch (e: MyFlowException) {
// complete
} finally {
if (!second.isClosedForReceive) second.cancel(MyFlowException())
if (!third.isClosedForReceive) third.cancel(MyFlowException())
}
}
class MyFlowException: CancellationException()
我对流动还不熟悉,但这似乎对我有用
// This will hold all 3 values
data class Foo(val i: Int, val j: Int, val k: Int)
val flow1 = (1..10).asFlow()
val flow2 = (11..20).asFlow()
val flow3 = (21..30).asFlow()
val combinedFlow = flow1.zip(flow2) {i, j ->
Pair(i, j)
}.zip(flow3) {pair, k ->
Foo(pair.first, pair.second, k)
}
然后,您将收集它们并按如下方式获取值:
zip(flow1, flow2, flow3) { a, b, c ->
Triple(a, b, c)
}
viewModelScope.launch {
repo.combinedFlow.collect {foo ->
System.out.println(foo.i)
System.out.println(foo.j)
System.out.println(foo.k)
}
}
流量具有组合功能
fun <T1, T2, R> Flow<T1>.combine(
flow: Flow<T2>,
transform: suspend (a: T1, b: T2) -> R
): Flow<R>
显然,但我想你可以先把前两个拉链拉上,然后再把下一个拉链拉上,再把下一个拉链拉上,但它不会像你想象的那样平行。
fun <T1, T2, R> Flow<T1>.combine(
flow: Flow<T2>,
transform: suspend (a: T1, b: T2) -> R
): Flow<R>
val flow = flowOf(1, 2).onEach { delay(10) }
val flow2 = flowOf("a", "b", "c").onEach { delay(15) }
combine(flow, flow2) { i, s -> i.toString() + s }.collect {
println(it) // Will print "1a 2a 2b 2c"
}