我经常偶然发现这个问题,但没有看到一个常见的实现:我如何惯用地(功能上)找到一个元素,在匹配后停止搜索,并返回一个不同的类型(即映射任何匹配到另一种类型)?
我已经能够做一个解决方法
fun <F,T> Sequence<F>.mapFirst(block: (F) -> T?): T? =
fold(AtomicReference<T>()) { ref, from ->
if (ref.get() != null) return@fold ref
ref.set(block(from))
ref
}.get()
fun main() {
Files.list(someDir).asSequence().map { it.toFile() }.mapFirst { file ->
file.useLines { lines ->
lines.mapFirst { line ->
if (line == "123") line.toInt() else null
}
}
}?.let { num ->
println("num is $num") // will print 123 as an Int
} ?: println("not a single file had a line eq to '123'")
}
但这并没有在比赛中停止(当
block()
返回非空值时)并且会消耗所有文件及其所有行。
最佳答案
一个简单的for
循环足以实现 mapFirst
:
fun <F,T> Sequence<F>.mapFirst(block: (F) -> T?): T? {
for (e in this) {
block(e)?.let { return it }
}
return null
}
如果您需要一个不引入您自己的扩展的解决方案(尽管它没有任何问题),您可以使用
mapNotNull
+ firstOrNull
组合:files.asSequence()
.mapNotNull { /* read the first line and return not null if it's ok */ }
.firstOrNull()
关于kotlin - Kotlin 中序列的查找和转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54601063/