给定一个来自遗留库的类,它的行为类似于
Iterator
,这样您就可以使用 hasNext
和 next
遍历它的内容,但它没有实现 Iterator
接口:
class LegacyIterator[T](iterable: Iterable[T]) {
val iterator: Iterator[T] = iterable.iterator
def hasNext: Boolean = iterator.hasNext
def next(): T = iterator.next()
}
val lagIter: LegacyIterator[Int] = new LegacyIterator(List(1, 2, 3))
您对遍历此类数据结构的最优雅方式有何看法 - 最好是在函数范围内?我想出了两个版本:
一个使用
@tailrec
@tailrec
def lagIterList(accu: List[Int]): List[Int] =
if (lagIter.hasNext) lagIterList(lagIter.next() :: accu) else accu
val res = lagIterList(Nil).reverse
还有一个使用
LazyList
def ll: LazyList[Int] = if(lagIter.hasNext) lagIter.next() #:: ll else LazyList.empty
val res = ll.toList
你认为什么更符合 Scala 的习惯?
tailrec
版本在较大的数据结构上可能稍微快一些,但 LazyList
版本更好地利用集合库。
或任何其他想法?
我会考虑一个扩展 Iterator[T] 的隐式包装类:
implicit class LegacyIteratorWrapper[T](private val underlying: LegacyIterator[T]) extends Iterator[T] {
override def hasNext: Boolean = underlying.hasNext
override def next(): T = underlying.next()
}
val lagIter: LegacyIterator[Int] = new LegacyIterator(List(1, 2, 3))
// traversal
for (elem <- lagIter) println(elem)
// conversion to list
val lagIterList = lagIter.toList
只需将其转换为普通迭代器即可:
val normalIterator = Iterator.continually(legacyIterator)
.takeWhile(_.hasNext)
.map(_.next)
然后您可以使用任何常规的 Scala 工具来遍历/转换它,例如:
val list = normalIterator.toList
嗯,这取决于你所说的“遍历它”是什么意思。 如果你只是想用它创造一个
List
,我会用unfold
def toList[T](iter: LegacyIterator[T]): List[T] =
List.unfold(()) { _ =>
Option.when(iter.hasNext()) {
iter.next() -> ()
}
}
foreach 方法采用一个应用于集合中每个元素的函数,允许您对每个元素执行操作而无需显式迭代:
val it = Iterator(1, 2, 3, 4, 5)
it.foreach { element =>
println(s"The current element is: $element")
}
在 Scala 中使用
foreach
优于 explicit iteration 因为它更简洁并且通常更有效。 foreach
方法也可以用在函数式风格中,允许您在一个表达式中将多个操作链接在一起:
val result = Iterator(1, 2, 3, 4, 5)
.filter(_ % 2 == 0)
.map(_ * 2)
.toList