We all know that java.util.Scanner
is slow.
Here is a version in Scala that is idiomatic (you can do all the Collections API e.g. .take
, .map
, .filter
etc) and supports line numbers too and is much faster than the Java Scanner:
import java.io._
import java.nio.file.{Files, Path}
import java.util.StringTokenizer
import scala.collection.JavaConversions._
import scala.io.Codec
/**
* Scala implementation of a faster java.util.Scanner
* See: http://codeforces.me/blog/entry/7018
*/
class Scanner(reader: LineNumberReader) extends Iterator[String] with AutoCloseable {
def this(reader: BufferedReader) = this(new LineNumberReader(reader))
def this(reader: Reader) = this(new BufferedReader(reader))
def this(inputStream: InputStream)(implicit codec: Codec) = this(new InputStreamReader(inputStream, codec.charSet))
def this(path: Path)(implicit codec: Codec) = this(Files.newBufferedReader(path, codec.charSet))
def this(file: File)(implicit codec: Codec) = this(file.toPath)(codec)
def this(str: String) = this(new StringReader(str))
val lines: Iterator[String] = reader.lines().iterator()
def tokens: Iterator[String] = for {
line <- lines
tokenizer = new StringTokenizer(line)
_ <- Iterator.continually(tokenizer).takeWhile(_.hasMoreTokens)
} yield tokenizer.nextToken()
private[this] var current = tokens
override def hasNext = current.hasNext
@inline override def next() = current.next()
/**
* @return Unlike the Java scanner which returns till end of current line, this actually returns the next line
*/
def nextLine(): String = {
val line = reader.readLine()
current = tokens // reset
line
}
def lineNumber: Int = reader.getLineNumber
def nextString(): String = next()
def nextBoolean(): Boolean = next().toBoolean
def nextByte(radix: Int = 10): Byte = java.lang.Byte.parseByte(next(), radix)
def nextShort(radix: Int = 10): Short = java.lang.Short.parseShort(next(), radix)
def nextInt(radix: Int = 10): Int = java.lang.Integer.parseInt(next(), radix)
def nextLong(radix: Int = 10): Long = java.lang.Long.parseLong(next(), radix)
def nextBigInt(radix: Int = 10): BigInt = BigInt(next(), radix)
def nextFloat(): Float = next().toFloat
def nextDouble(): Double = next().toDouble
def nextBigDecimal(): BigDecimal = BigDecimal(next())
override def close() = reader.close()
}
Source: https://github.com/pathikrit/ScalaForces/blob/master/src/main/scala/Scanner.scala
Benchmarks: https://github.com/pathikrit/better-files/tree/master/benchmarks