经过一些反复试验后,我找到了一种结束Stream.iterate
的方法(如果标准输入在我的情况下结束)。但对我而言,它似乎更像是一种邪恶的黑客,而不是最佳实践解决方案。
之前(未结束,如果标准输入因<{1}}无限运行而结束):
Stream.iterate
之后(现在按预期工作):
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
}
正如您所看到的,引入了几个新的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
是否达到目的。
我怎样才能以更优雅的形式编写此功能?
答案 0 :(得分:2)
如果我理解你正在做的事情,这将以更简单的方式解决你的问题:
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
速度很慢,并且memoization很容易导致内存泄漏。 Iterator
具有创建有限或无限延迟序列的所有相同方法,并且应该是用于此目的的首选集合。
答案 1 :(得分:1)
我想知道事情是否变得有点复杂,Streams中的Streams和scanLeft()
内的iterate()
等等。投入Option
类型以确定{{ 1}} - end有一种腥味。
Stream
具有自然结束条件。我想知道这样的事情是否会更好。
Iterator
我不知道这是否真的有效。我没有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
}
类型可供使用。
我改变了&#34;继续&#34;从Document
到line != null
的条件,以便它将在任何空输入上结束,而不只是Option(line).fold(false)(_.nonEmpty)
。它只是让测试变得更容易。