Scala遍历类迭代器数据结构的惯用方法

h7appiyu  于 2023-03-02  发布在  Scala
关注(0)|答案(3)|浏览(158)

给定一个来自遗留库的类,其行为类似于Iterator,因此您可以使用hasNextnext遍历其内容,但它不实现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版本更好地利用了集合库。
或者其他的想法?

xtfmy6hx

xtfmy6hx1#

我会考虑使用一个隐式 Package 器类来扩展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
cwxwcias

cwxwcias2#

把它转换成一个普通的迭代器:

val normalIterator = Iterator.continually(legacyIterator)
  .takeWhile(_.hasNext)
  .map(_.next)

然后你可以使用任何常规的scala工具来遍历/转换它,例如:val list = normalIterator.toList

rsaldnfx

rsaldnfx3#

好吧,这取决于您所指的 “遍历它”。如果您的意思只是从它创建一个List,我将直接使用unfold

def toList[T](iter: LegacyIterator[T]): List[T] =
  List.unfold(()) { _ =>
    Option.when(iter.hasNext()) {
      iter.next() -> ()
    }
  }

相关问题