经过一些尝试和错误之后,我找到了一种结束的方法(如果在我的例子中标准输入结束的话)。但在我看来,这更像是一种邪恶的攻击,而不是一种最佳实践解决方案。
在之前(如果标准输入结束,则不结束,因为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类型值。他们唯一的目的是告诉takeWhile,如果达到目的。
如何以更优雅的形式编写此功能?
发布于 2018-04-18 17:38:16
如果我正确理解你所做的事情,这将以一种更简单的方式解决你的问题:
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有所有相同的好方法来创建有限的或无限的惰性序列,并且应该是用于这个目的的首选集合。
发布于 2018-04-18 07:54:01
我想知道事情是否变得太复杂了,为什么流中的流,iterate()中的iterate()等等,为了确定Stream-end而加入Option类型,对它有一种可疑的感觉。
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
}我不知道这是否真的管用。我没有你的Document类型可以使用。
我将“继续”条件从line != null更改为Option(line).fold(false)(_.nonEmpty),以便在任何空输入(而不仅仅是null )上结束。这只会让测试变得更容易。
https://stackoverflow.com/questions/49884078
复制相似问题