Reputation:
Trying to learn Scala using the Programming in Scala book and they have a very basic example for reading lines from a file. I'm trying to expand on it and read a file line by line, look for a certain phrase, then print the next 6 lines following that line if it finds the line. I can write the script easily enough in something like java or Perl but I have no idea how to do it in Scala (probably because I'm not very familiar with the language yet...)
Here's the semi adapted sample code from the Programming in Scala book,
import scala.io.Source
if(args.length>0) {
val lines = Source.fromFile(args(0)).getLines().toList
for(line<-lines) {
if(line.contains("secretPhrase")) {
println(line)
//How to get the next lines here?
}
}
}
else
Console.err.println("Pleaseenterfilename")
Upvotes: 2
Views: 1842
Reputation: 527
Views are the secret sauce that makes iterating lists efficient in scala. Try this:
val l = Source.fromFile(args(0)).getLines().toList
l.view.zipWithIndex.filter(_._1.contains("secretPhrase")).foreach {
case (s, i) => l.view(i+1, i+7).foreach(println(_))
}
Upvotes: 2
Reputation: 51109
Using for
on a collection just references that element, which is why you can't reference the following lines. If you need to reference the collection itself, there are a couple of ways:
1) use a built-in method. The appropriate one is tails
. For instance, if our collection is List("a","b","c")
,
scala> List("a","b","c").tails foreach println
List(a, b, c)
List(b, c)
List(c)
List()
This is almost what we need, except we don't want to check the empty List()
at the end, so we can either a) put in a check that the list is not empty:
lines.tails foreach { xs =>
if (!xs.isEmpty && (xs.head contains "secretPhrase"))
xs take 6 foreach println
}
or b) use init
to take all elements except the last:
lines.tails.toList.init foreach { xs =>
if (xs.head contains "secretPhrase")
xs take 6 foreach println
}
2) while loop / recursion.
a) while loop:
var xs = lines
while (!xs.isEmpty) {
if (xs.head contains "secretPhrase")
xs take 6 foreach println
xs = xs.tail
}
b) equivalent recursion
def print6(xs: List[String]): Unit = if (!xs.isEmpty) {
if (xs.head contains "secretPhrase")
xs take 6 foreach println
print6(xs.tail)
}
print6(lines)
Upvotes: 1
Reputation: 3381
You can replace the for expression with something like this:
lines.sliding(7).filter(l => l(0).contains("secretPhrase")).foreach(println)
Note that this will miss the secret phrase if it's in the last 6 lines because of the way sliding works (it stops when it first encounters the end of the list).
You could work around this in a number of ways, the simplest perhaps being to append six dummy lines to the list before processing.
Upvotes: 2
Reputation: 8139
You could do it similar to how it's done in java
if(args.length > 0) {
val lines = Source.fromFile(args(0)).getLines.toList
for(i <- 0 until lines.size) {
if(lines(i).contains("secretPhrase")) {
for(j <- i+1 to i+6) println(lines(j))
}
}
}
or you use scala idioms to make it shorter
if(args.length > 0) {
val lines = Source.fromFile(args(0)).getLines
lines.dropWhile(!_.contains("secretPhrase"))
.drop(1).take(6).foreach(println)
}
Upvotes: 8