Kotlin 流程:仅收集至少重复 N 次的元素

Kotlin flow: collect only elements which repeat at least N times

我正在实现 ML Kit OCR 功能,有时前几个值是错误的,只有在一段时间后相机稳定并产生正确的值。我不想删除第一个 X 值,因为我不知道流程将包含多少元素。所以最好的方法是使用一些条件,将当前元素与前一个元素进行比较,但不确定。

Kotlin Flow API 中是否有一个函数可以比较收集到的值并只收集至少出现 N 次的值?

  private val _detectedValues = ConflatedBroadcastChannel<String>()
  val detectedFlow = _detectedValues
      .asFlow()
      .map { it.replace(" ", "") }
      .filter { it.checkRegex() }
      .onEach {
          Log.i(TAG, "detected: $it")
      }

据我所知,没有内置的方法可以做到这一点,但你可以做一个:

fun <T> Flow<T>.repeated(times: Int): Flow<T> {
    val map = mutableMapOf<T, Int>()
    return transform { value ->
        val count = (map[value] ?: 0) + 1
        map[value] = count
        if (count >= times) {
            return@transform emit(value)
        }
    }
}

这使用映射来跟踪每个值已发出的次数。然后,如果一个值被发出足够多次,它就会通过转换发出。

channel.asFlow()
        .repeated(3)
        .collect {
            // Do something.
        }

编辑: 它绝对有效。这是测试代码:

suspend fun test() = coroutineScope {
    val flow = MutableSharedFlow<String>()
    launch {
        flow.repeated(3).collect { value ->
            println("received: $value")
        }
    }
    launch {
        while (true) {
            val value = listOf("a", "b", "c").random()
            println("emitted: $value")
            flow.emit(value)
            delay(1000)
        }
    }
}

我得到以下输出:

emitted: c
emitted: a
emitted: c
emitted: c
received: c
emitted: b
emitted: b
emitted: b
received: b
emitted: a
emitted: a
received: a
emitted: a
received: a
emitted: b
received: b