Scala:从stdin读取时扫描左后一项

ide*_*xer 6 iterator scala

如果我从处理输入stdinscanLeft,输出结果永远是我最后输入后面一行:

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不应该在累积回调中调用该命令,而是在我可以预先设置的不同链链接中调用.

And*_*kin 5

编辑摘要:添加了一个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)


jwv*_*wvh 3

你可以得到与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 模式的方法添加到调用链中。