gpt4 book ai didi

kotlin - 窥探迭代器

转载 作者:行者123 更新时间:2023-12-03 07:50:45 27 4
gpt4 key购买 nike

Kotlin 中是否有一种方法可以“窥视”迭代器的下一个元素而不推进它?对于示例用例,请考虑此函数用于合并两个预排序的序列:

fun merge(seq1: Sequence<Int>, seq2: Sequence<Int>) = sequence<Int> {
val it1 = seq1.iterator()
var current1 = if (it1.hasNext()) it1.next() else null
val it2 = seq2.iterator()
var current2 = if (it2.hasNext()) it2.next() else null

while (current1 != null && current2 != null) {
if (current1 <= current2) {
yield(current1)
current1 = if (it1.hasNext()) it1.next() else null
} else {
yield(current2)
current2 = if (it2.hasNext()) it2.next() else null
}
}
while (current1 != null) {
yield(current1)
current1 = if (it1.hasNext()) it1.next() else null
}
while (current2 != null) {
yield(current2)
current2 = if (it2.hasNext()) it2.next() else null
}
}

这个函数必须跳过重重困难,因为Iterator接口(interface)无法在不前进的情况下请求下一个元素。换句话说,它不尊重 Command-Query Separation Principle .

如果我使用 Guava 的 PeekingIterator ,我可以使这个函数更加简洁和可读。 :

fun merge(seq1: Sequence<Int>, seq2: Sequence<Int>) = sequence<Int> {
val it1: PeekingIterator<Int> = Iterators.peekingIterator(seq1.iterator())
val it2: PeekingIterator<Int> = Iterators.peekingIterator(seq2.iterator())

while (it1.hasNext() && it2.hasNext())
yield((if (it1.peek() <= it2.peek()) it1 else it2).next())
yieldAll(it1)
yieldAll(it2)
}

相同的功能从 24 行减少到 9 行!然而,我在 Kotlin 项目中使用 Guava 感觉不太舒服。 Guava 的创建是为了解决 Java API 的一些限制。 Kotlin 标准库要丰富得多,我们不需要使用第三方 Java 库。有没有办法在不使用 Guava 的情况下使第一个代码示例更加简洁和可读?

附录

这是上述函数的示例单元测试,它应该让您了解它的行为方式:

import io.kotest.core.spec.style.FreeSpec
import io.kotest.matchers.shouldBe

class MyTest : FreeSpec({
"merge test" {
merge(emptySequence(), emptySequence()).toList() shouldBe emptyList()
merge(emptySequence(), sequenceOf(1)).toList() shouldBe listOf(1)
merge(emptySequence(), sequenceOf(1, 3)).toList() shouldBe listOf(1, 3)
merge(sequenceOf(1), emptySequence()).toList() shouldBe listOf(1)
merge(sequenceOf(1, 3), emptySequence()).toList() shouldBe listOf(1, 3)
merge(sequenceOf(0, 3, 4), sequenceOf(1, 4, 7)).toList() shouldBe listOf(0, 1, 3, 4, 4, 7)
}
)

最佳答案

我认为 Kotlin stdlib 没有提供这个,但我们可以自己实现:

fun main() {
val iter = listOf(1, 2, 3).iterator().peeking()

println(iter.next()) // 1
println(iter.peek()) // 2
println(iter.peek()) // 2
println(iter.next()) // 2
println(iter.peek()) // 3
println(iter.next()) // 3
println(iter.peek()) // NoSuchElementException
}

fun <T> Iterator<T>.peeking() = object : PeekingIterator<T> {
private var hasPeeked = false
private var peeked: T? = null

override fun hasNext(): Boolean = hasPeeked || <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2e5a46475d6e5e4b4b4547404900464f5d604b565a" rel="noreferrer noopener nofollow">[email protected]</a>()

override fun next(): T {
return if (hasPeeked) {
hasPeeked = false
@Suppress("UNCHECKED_CAST")
peeked as T
} else {
<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="691d01001a29190c0c0200070e47070c111d" rel="noreferrer noopener nofollow">[email protected]</a>()
}
}

override fun peek(): T {
if (!hasPeeked) {
peeked = <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a1d5c9c8d2e1d1c4c4cac8cfc68fcfc4d9d5" rel="noreferrer noopener nofollow">[email protected]</a>()
hasPeeked = true
}
@Suppress("UNCHECKED_CAST")
return peeked as T
}
}

interface PeekingIterator<T> : Iterator<T> {
fun peek(): T
}

关于kotlin - 窥探迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77174295/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com