请考虑以下两类:
class ObjectA(val objectBs: List<ObjectB>,
val otherFields: Any)
class ObjectB(val key: String,
val otherFields: Any)
Run Code Online (Sandbox Code Playgroud)
任务是在ObjectA列表中查找并返回具有特定键的第一个ObjectB。
仅仅实现目标就足够简单了,但是很好而有效地做到这一点似乎很棘手。我找不到“ firstIn”或“ findIn”函数之类的东西,该函数使我在迭代ObjectA列表时可以返回ObjectA以外的其他类型。
我有几种方法,其中一种看起来不错,但效率很低:
listOfA.mapNotNull {
it.objectBs.firstOrNull {
item -> item.key == wantedKey
}
}.firstOrNull()
Run Code Online (Sandbox Code Playgroud)
该代码的明显低效之处在于,找到匹配项后,它不会停止通过listOfA进行迭代(并且只有一个匹配项,请注意)。使用过滤器或查找的方法也有类似的问题,需要遍历至少一个ObjectB列表进行冗余迭代。
kotlins标准库中是否有可以涵盖此类用例的内容?
Shr*_* Ye 10
通过将所有嵌套元素转换为扁平化Sequence,它们可以被延迟迭代,并且消除了不必要的迭代的开销。这个技巧是通过组合asSequence和来完成的flatMap:
listOfA.asSequence().flatMap { it.objectBs.asSequence() }.find { it.key == wantedKey }
Run Code Online (Sandbox Code Playgroud)
我编写并运行了以下代码以确保其按预期工作:
class PrintSequenceDelegate<out T>(private val wrappedSequence: Sequence<T>) : Sequence<T> by wrappedSequence {
override fun iterator(): Iterator<T> {
val wrappedIterator = wrappedSequence.iterator()
return object : Iterator<T> by wrappedIterator {
override fun next(): T =
wrappedIterator.next().also { println("Retrieving: $it") }
}
}
}
fun <T> Sequence<T>.toPrintDelegate() = PrintSequenceDelegate(this)
fun main() {
val listOfLists = List(3) { i -> List(3) { j -> "$i$j" } }
println("List of lists: $listOfLists")
val found = listOfLists.asSequence().toPrintDelegate().flatMap { it.asSequence().toPrintDelegate() }.find { it == "11" }
println(if (found != null) "Found: $found" else "Not found")
}
Run Code Online (Sandbox Code Playgroud)
输出:
listOfA.asSequence().flatMap { it.objectBs.asSequence() }.find { it.key == wantedKey }
Run Code Online (Sandbox Code Playgroud)
因此,我们看到12包含嵌套列表中找到的元素之后的元素 ( ) 不会被迭代,后面的嵌套列表 ( [20, 21, 22]) 也不会被迭代。
如果你想要一个优雅的解决方案,你可以这样做flatMap:
val result: ObjectB? = listOfA.flatMap { it.objectBs }.firstOrNull { it.key == "myKey" }
Run Code Online (Sandbox Code Playgroud)
如果你想要效率,你可以这样做:
val result: ObjectB? = objectAs.firstOrNull {
it.objectBs.map(ObjectB::key).contains("myKey")
}?.objectBs?.firstOrNull { it.key == "myKey" }
Run Code Online (Sandbox Code Playgroud)
您还可以将这些包装在一个 中Optional并将其放入一个函数中,以便此操作的用户可以拥有一个干净的 API:
fun List<ObjectA>.findFirstObjectB(key: String): Optional<ObjectB> {
return Optional.ofNullable(firstOrNull {
it.objectBs.map(ObjectB::key).contains(key)
}?.objectBs?.firstOrNull { it.key == key })
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3288 次 |
| 最近记录: |