获取流程收集中的当前和先前值

问题描述 投票:0回答:3

我需要处理流收集中的当前值和先前值,因此我需要一些具有类似功能的运算符:

----A----------B-------C-----|--->

---(null+A)---(A+B)---(B+C)--|--->

一个想法是这样的:

fun <T: Any> Flow<T>.withPrevious(): Flow<Pair<T?, T>> = flow {
    var prev: T? = null
    [email protected] {
        emit(prev to it)
        prev = it
    }
}

但是这样就无法控制执行第一个流程的上下文。有更灵活的解决方案吗?

kotlin kotlin-coroutines coroutine kotlin-flow coroutinescope
3个回答
12
投票

有一个运算符可以让这变得非常简单:

runningFold

文档有一个关于如何使用它来收集流的每次发射的示例;这可以很容易地适应我们的需求

data class History<T>(val previous: T?, val current: T)

// emits null, History(null,1), History(1,2)...
fun <T> Flow<T>.runningHistory(): Flow<History<T>?> =
    runningFold(
        initial = null as (History<T>?),
        operation = { accumulator, new -> History(accumulator?.current, new) }
    )

// doesn't emit until first value History(null,1), History(1,2)...
fun <T> Flow<T>.runningHistoryAlternative(): Flow<History<T>> =
    runningHistory().filterNotNull()

您可能需要调整可空性以适合您的用例


4
投票

Flow
是连续的,因此您可以使用变量来存储先前的值:

coroutineScope.launch {
    var prevValue = null
    flow.collect { newValue ->
        // use prevValue and newValue here
        ...
        // update prevValue
        prevValue = newValue
    }
}

0
投票

我认为您可以使用

runningFold
轻松完成此操作,因为使用它,您可以使用折叠操作将一个流程转换为另一个流程。这是因为
runningFold
确实将所有内容折叠成一个值,如
fold
。相反,它将所有步骤保留为所有突变的历史记录。您唯一需要关心的是每个返回值必须是一对,第一个值必须为 null,并且第一个对的左侧值必须允许为 null。允许 null 作为累加器也意味着必须过滤掉该值。

粗略地说,您需要遵循这样的示例:

val initial: Pair<String?, String>? = null
val allPairs = flow {
    emit("Oyster")
    emit("Clam")
    emit("Crab")
}.runningFold(initial) { lastPair, next ->
    lastPair?.run {
        val (_, last) = this
        last to next
    } ?: (null to next)

}.filterNotNull()
allPairs.collect {
    println(it)
}

这样您就不需要创建运营商类别类型,因为您的运营商类别已经是

Pair
类别。

您可以使用

fold
测试差异,如下所示:

val initial: Pair<String?, String>? = null
val pair = flow {
    emit("Oyster")
    emit("Clam")
    emit("Crab")
}.fold(initial) { lastPair, next ->
    lastPair?.run {
        val (_, last) = this
        last to next
    } ?: (null to next)

}
println(pair)

在此处查看有关折叠及其不同形式的更多信息:

  1. 折叠

  2. 运行折叠

  3. kotlin.collections

© www.soinside.com 2019 - 2024. All rights reserved.