如果我使用stdin
处理来自scanLeft
的输入,则结果输出总是在我上一次输入后面一行:
io.Source.stdin
.getLines
.scanLeft("START:")((accu, line) => accu + " " + line)
.foreach(println(_))
结果(我的手动输入前面有>
):
> first
START:
> second
START: first
> third
START: first second
我想要的合理输出是:
> first
START: first
> second
START: first second
> third
START: first second third
如您所见,第一个输入行后面的输出应该已经包含第一个输入行的字符串。
我已经使用.scanLeft(...).drop(1).foreach(...)
尝试过了,但这导致了以下结果:
> first
> second
START: first
> third
START: first second
如何正确省略纯种子以获得所需结果?
[UPDATE] 目前,我很满意安德烈泰金的精彩解决方法。非常感谢你的建议。
但是,当然,如果有scanLeft
的替代品没有将种子作为第一项发送到下一个迭代链中,我会更喜欢这个解决方案。
[UPDATE]
用户 jwvh 了解我的目标并提供了一个出色的解决方案。为了完善他们的建议,我寻求一种预处理线路的方法,然后再将它们发送到累积回调中。因此,readLine
命令不应该在累积回调中调用,而是在我可以添加的不同链链接中调用。
答案 0 :(得分:5)
编辑摘要:添加了map
,以证明getLines
返回的行的预处理同样重要。
您可以将println
移动到scanLeft
本身,强制立即执行而不会出现延迟:
io.Source.stdin
.getLines
.scanLeft("START:") {
(accu, line) => accu + " " + line
val res = accu + " " + line
println(res)
res
}.foreach{_ => }
然而,这似乎与更短更直观的foldLeft
:
io.Source.stdin
.getLines
.foldLeft("START:") {
(accu, line) => accu + " " + line
val res = accu + " " + line
println(res)
res
}
互动示例:
first
START: first
second
START: first second
third
START: first second third
fourth
START: first second third fourth
fifth
START: first second third fourth fifth
sixth
START: first second third fourth fifth sixth
seventh
START: first second third fourth fifth sixth seventh
end
START: first second third fourth fifth sixth seventh end
编辑
您当然可以添加map
步骤来预处理这些行:
io.Source.stdin
.getLines
.map(_.toUpperCase)
.foldLeft("START:") {
(accu, line) => accu + " " + line
val res = accu + " " + line
println(res)
res
}
示例交互(键入小写,打印大写):
> foo
START: FOO
> bar
START: FOO BAR
> baz
START: FOO BAR BAZ
答案 1 :(得分:3)
您可以使用Stream.iterate()
代替scanLeft()
和StdIn.readLine
代替stdin.getLines
获得非常相似的内容。
def input = Stream.iterate("START:"){prev =>
val next = s"$prev ${io.StdIn.readLine}"
println(next)
next
}
由于Stream
被懒惰地评估,你需要一些方法来实现它。
val inStr = input.takeWhile(! _.contains("quit")).last
START: one //after input "one"<return>
START: one two //after input "two"<return>
START: one two brit //after input "brit"<return>
START: one two brit quit //after input "quit"<return>
//inStr: String = START: one two brit
如果这是一个要求,你实际上不必放弃getLines
迭代器。
def inItr = io.Source.stdin.getLines
def input = Stream.iterate("START:"){prev =>
val next = s"$prev ${inItr.next}"
println(next)
next
}
不确定这是否符合您的意见。很多情况取决于可能出现的错误以及确定错误的方式。
Stream.iterate(document()){ doc =>
val line = io.StdIn.readLine //blocks here
.trim
.filterNot(_.isControl)
//other String or Char manipulations
doc.update(line)
/* at this point you have both input line and updated document to play with */
... //handle error and logging requirements
doc //for the next iteration
}
我假设.update()
修改源文档并且不返回任何内容(返回Unit
)。这是update()
方法的常用签名。
大部分内容都可以在调用链中完成(_.method1.method2.
等),但有时这会让事情变得更复杂。
通过使用名为kestrel pattern的内容,仍然可以将不返回感兴趣值的方法添加到调用链中。