If I process the input from stdin
with scanLeft
, the resulting output is always one line behind my last input:
io.Source.stdin
.getLines
.scanLeft("START:")((accu, line) => accu + " " + line)
.foreach(println(_))
Results in (my manual inputs are preceded by >
):
> first
START:
> second
START: first
> third
START: first second
The sensible output I want is:
> first
START: first
> second
START: first second
> third
START: first second third
As you can see, the output following the first input line should already contain the string of the first input line.
I already tried it using .scanLeft(...).drop(1).foreach(...)
, but this leads to the following result:
> first
> second
START: first
> third
START: first second
How do I correctly omit the pure seed to get the desired result?
[UPDATE] For the time being I am content with Andrey Tyukin's nifty workaround. Many thanks for suggesting it.
But of course, if there is any alternative to scanLeft
that does not send the seed as first item into the following iteration chain, I will prefer that solution.
[UPDATE]
User jwvh understood my objective and provided an excellent solution to it. To round off their suggestion I seek a way of preprocessing the lines before sending them into the accumulation callback. Thus the readLine
command should not be called in the accumulation callback but in a different chain link I can prepend.
Edit Summary: Added a map
to demonstrate that the preprocessing of lines returned by getLines
is just as trivial.
You could move println
into the body of scanLeft
itself, to force immediate execution without the lag:
io.Source.stdin
.getLines
.scanLeft("START:") {
(accu, line) => accu + " " + line
val res = accu + " " + line
println(res)
res
}.foreach{_ => }
However, this seems to behave exactly the same as a shorter and more intuitive foldLeft
:
io.Source.stdin
.getLines
.foldLeft("START:") {
(accu, line) => accu + " " + line
val res = accu + " " + line
println(res)
res
}
Example interaction:
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
EDIT
You can of course add a map
-step to preprocess the lines:
io.Source.stdin
.getLines
.map(_.toUpperCase)
.foldLeft("START:") {
(accu, line) => accu + " " + line
val res = accu + " " + line
println(res)
res
}
Example interaction (typed lowercase, printed uppercase):
> foo
START: FOO
> bar
START: FOO BAR
> baz
START: FOO BAR BAZ
You can get something pretty similar with Stream.iterate()
in place of scanLeft()
and StdIn.readLine
in place of stdin.getLines
.
def input = Stream.iterate("START:"){prev =>
val next = s"$prev ${io.StdIn.readLine}"
println(next)
next
}
Since a Stream
is evaluated lazily you'll need some means to materialize it.
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
You actually don't have to give up on the getLines
iterator if that's a requirement.
def inItr = io.Source.stdin.getLines
def input = Stream.iterate("START:"){prev =>
val next = s"$prev ${inItr.next}"
println(next)
next
}
Not sure if this addresses your comments or not. Lots depends on where possible errors might come from and how they are determined.
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
}
I've assumed that .update()
modifies the source document and returns nothing (returns Unit
). That's the usual signature for an update()
method.
Much of this can be done in a call chain (_.method1.method2.
etc.) but sometimes that just makes things more complicated.
Methods that don't return a value of interest can still be added to a call chain by using something called the kestrel pattern.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With