如果我从处理输入stdin用scanLeft,输出结果永远是我最后输入后面一行:
io.Source.stdin
.getLines
.scanLeft("START:")((accu, line) => accu + " " + line)
.foreach(println(_))
Run Code Online (Sandbox Code Playgroud)
结果(我的手动输入前面有>):
> first
START:
> second
START: first
> third
START: first second
Run Code Online (Sandbox Code Playgroud)
我想要的合理输出是:
> first
START: first
> second
START: first second
> third
START: first second third
Run Code Online (Sandbox Code Playgroud)
如您所见,第一个输入行后面的输出应该已经包含第一个输入行的字符串.
我已经尝试过使用它.scanLeft(...).drop(1).foreach(...),但这会导致以下结果:
> first
> second
START: first
> third
START: first second
Run Code Online (Sandbox Code Playgroud)
如何正确省略纯种子以获得所需结果?
[更新]暂时我很满意安德烈泰金的精彩解决方法.非常感谢你的建议.
但是,当然,如果有任何替代方案scanLeft不会将种子作为第一项发送到下一个迭代链中,我将更喜欢该解决方案.
[UPDATE]
用户jwvh理解我的目标并提供了一个很好的解决方案.为了完善他们的建议,我寻求一种预处理线路的方法,然后再将它们发送到累积回调中.因此,readLine不应该在累积回调中调用该命令,而是在我可以预先设置的不同链链接中调用.
编辑摘要:添加了一个map来证明返回的行的预处理getLines同样简单.
你可以println进入scanLeft自己的身体,迫使立即执行没有滞后:
io.Source.stdin
.getLines
.scanLeft("START:") {
(accu, line) => accu + " " + line
val res = accu + " " + line
println(res)
res
}.foreach{_ => }
Run Code Online (Sandbox Code Playgroud)
但是,这似乎与更短更直观的行为完全相同foldLeft:
io.Source.stdin
.getLines
.foldLeft("START:") {
(accu, line) => accu + " " + line
val res = accu + " " + line
println(res)
res
}
Run Code Online (Sandbox Code Playgroud)
示例交互:
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
Run Code Online (Sandbox Code Playgroud)
编辑
您当然可以添加一个步骤map来预处理这些行:
io.Source.stdin
.getLines
.map(_.toUpperCase)
.foldLeft("START:") {
(accu, line) => accu + " " + line
val res = accu + " " + line
println(res)
res
}
Run Code Online (Sandbox Code Playgroud)
示例交互(键入的小写,打印大写):
> foo
START: FOO
> bar
START: FOO BAR
> baz
START: FOO BAR BAZ
Run Code Online (Sandbox Code Playgroud)
你可以得到与Stream.iterate()in place ofscanLeft()和StdIn.readLinein place of非常相似的东西stdin.getLines。
def input = Stream.iterate("START:"){prev =>
val next = s"$prev ${io.StdIn.readLine}"
println(next)
next
}
Run Code Online (Sandbox Code Playgroud)
由于 aStream是惰性评估的,因此您需要一些方法来实现它。
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
Run Code Online (Sandbox Code Playgroud)
getLines如果有需要,您实际上不必放弃迭代器。
def inItr = io.Source.stdin.getLines
def input = Stream.iterate("START:"){prev =>
val next = s"$prev ${inItr.next}"
println(next)
next
}
Run Code Online (Sandbox Code Playgroud)
不确定这是否解决了您的意见。这很大程度上取决于可能的错误可能来自何处以及如何确定它们。
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
}
Run Code Online (Sandbox Code Playgroud)
我假设.update()修改源文档并且不返回任何内容(返回Unit)。这是方法的常见签名update()。
其中大部分可以在调用链(等)中完成,_.method1.method2.但有时这只会使事情变得更加复杂。
不返回感兴趣值的方法仍然可以通过使用称为kestrel 模式的方法添加到调用链中。