首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scala:结束Stream.iterate

Scala:结束Stream.iterate
EN

Stack Overflow用户
提问于 2018-04-17 17:26:01
回答 2查看 365关注 0票数 2

经过一些尝试和错误之后,我找到了一种结束的方法(如果在我的例子中标准输入结束的话)。但在我看来,这更像是一种邪恶的攻击,而不是一种最佳实践解决方案。

之前(如果标准输入结束,则不结束,因为Stream.iterate运行无限):

代码语言:javascript
复制
val initialDocument = Document()
val in: Stream[Document] = Stream.iterate(Stream[Document]()) { documents =>
  val lastDocument: Document = documents.lastOption.getOrElse(initialDocument)
  val line: String = io.StdIn.readLine
  if(line != null) {
    line
      .split(";")
      .map(_.trim)
      .scanLeft(lastDocument)((document: Document, line: String) => document.processInput(line))
      .drop(1) // drop the seed
      .toStream
  } else {
    Stream.empty
  }
}.flatten
for(document <- in) {
  // do something with the document snapshot
}

之后的(现在按预期工作):

代码语言:javascript
复制
val initialDocument = Document()
val in: Stream[Document] = Stream.iterate(Stream[Option[Document]]()) { documents =>
  val lastDocument: Option[Document] = Some(documents.lastOption.flatten.getOrElse(initialDocument))
  val line: String = io.StdIn.readLine
  if(line != null) {
    line
      .split(";")
      .map(_.trim)
      .scanLeft(lastDocument)((document: Option[Document], line: String) => document.map(_.processInput(line)))
      .drop(1) // drop the seed
      .toStream
  } else {
    Stream(None) // "None" is used by "takeWhile" to see we have no more input
  }
}.flatten.takeWhile(_.isDefined).map(_.get)
for(document <- in) {
  // do something with the document snapshot
}

如您所见,引入了几个新的Option类型值。他们唯一的目的是告诉takeWhile,如果达到目的。

如何以更优雅的形式编写此功能?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-04-18 17:38:16

如果我正确理解你所做的事情,这将以一种更简单的方式解决你的问题:

代码语言:javascript
复制
val in = Iterator
  .continually(io.StdIn.readLine())       // Read all lines from StdIn infinitely
  .takeWhile(_ != null)                   // Stop on EOI
  .flatMap(_.split(';'))                  // Iterator of sublines
  .map(_.trim)                            // Iterator of trimmed sublines
  .scanLeft(Document())(_ processInput _) // Iterator of a Document snapshot per subline
  .drop(1)                                // Drop the empty Document

for (document -> in) {
  // do something with the document snapshot
}

基本上,首先从整个输入中创建一个裁剪行部件的延迟Iterator,然后根据这个迭代器生成文档快照。

最好避免使用Stream,除非您真的需要它的回忆录功能。Stream很慢,而且回忆录很容易导致内存泄漏。Iterator有所有相同的好方法来创建有限的或无限的惰性序列,并且应该是用于这个目的的首选集合。

票数 2
EN

Stack Overflow用户

发布于 2018-04-18 07:54:01

我想知道事情是否变得太复杂了,为什么流中的流,iterate()中的iterate()等等,为了确定Stream-end而加入Option类型,对它有一种可疑的感觉。

Iterator有一个自然的结束条件。我想知道这样的事情会不会更好。

代码语言:javascript
复制
class DocItr(private var prev :Document) extends Iterator[Document] {
  private var innerItr :Iterator[Document] = _
  private var line     :String = _

  override def hasNext :Boolean = innerItr.hasNext || {
    line = io.StdIn.readLine
    Option(line).fold(false)(_.nonEmpty)
  }

  override def next() :Document = {
    if (!innerItr.hasNext) {
      innerItr = line.split(";")
                     .map(_.trim)
                     .scanLeft(prev)((doc: Document, in: String) =>
                                                       doc.processInput(in))
                     .drop(1) // drop the seed
                     .toIterator
    }
    prev = innerItr.next()
    prev
  }
}

for(document <- new DocItr(initialDocument)) {
  // do something with the document snapshot
}

我不知道这是否真的管用。我没有你的Document类型可以使用。

我将“继续”条件从line != null更改为Option(line).fold(false)(_.nonEmpty),以便在任何空输入(而不仅仅是null )上结束。这只会让测试变得更容易。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49884078

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档