If you're interested in functional programming, you might also want to checkout my second blog which i'm actively working on!!

Thursday, July 11, 2013

CSVReader (Scala)

/**
I wanted to find out how much lines of code a simple easy to use CSVReader would take in Scala.
So here is a quick first try-out.
**/
package csv
import java.lang.Boolean
import scala.util.Try
import scala.io.Source
trait LineTokenizer {
def tokenize(line: String, separator: String): Array[String] =
line.split(separator).map(value => value.trim())
def tokenize(line: String, separator: String, labels: List[String]): FieldSet =
new FieldSet(labels, tokenize(line, separator))
}
trait LineMapper[T] {
def mapLine(fieldSet: FieldSet): T
}
class CSVReader[T](file: String, separator: String, labels: List[String], hasHeader: Boolean,
lineMapper: LineMapper[T]) extends LineTokenizer {
val lines = Source.fromFile(file).getLines()
val header = if (hasHeader) lines.next() else ""
def hasNext: Boolean = lines.hasNext
def next: T = lineMapper.mapLine(tokenize(lines.next(), separator, labels))
}
class FieldSet(labels: List[String], values: Array[String]) {
val fields = labels.zip(values).toMap
def readString(field: String): Option[String] = fields.get(field)
def readBoolean(field: String): Option[Boolean] =
convert(field, (s: String) => Boolean.valueOf(s))
def readInt(field: String): Option[Int] = convert(field, (s: String) => s.toInt)
def readLong(field: String): Option[Long] = convert(field, (s: String) => s.toLong)
def readBigDecimal(field: String): Option[BigDecimal] =
convert(field, (s: String) => BigDecimal.valueOf(s.toDouble))
def convert[T](field: String, f: String => T): Option[T] = {
readString(field) match {
case None => None
case Some(x) => Try[Option[T]](Some(f(x))).getOrElse(None)
}
}
override def toString =
List("FieldSet([", labels.mkString(","), "],[", values.mkString(","), "])").mkString
}
/***************** persons.csv ******************************************/
name, age, male
Robby, 36, true
Valerie, 6, false
Lindsey, 10, false
/**************** USAGE *************************************************/
import csv.{FieldSet, LineMapper, CSVReader}
import java.lang.Boolean
case class Person(name: String, age: Int, isMale: Boolean)
val NAME = "NAME"
val AGE = "AGE"
val IS_MALE = "IS_MALE"
val lineMapper = new LineMapper[Person] {
override def mapLine(fieldSet: FieldSet): Person = {
val name = fieldSet.readString(NAME).getOrElse("")
val age = fieldSet.readInt(AGE).getOrElse(0)
val isMale = fieldSet.readBoolean(IS_MALE).getOrElse(Boolean.FALSE)
Person(name, age , isMale)
}
}
val csvReader = new CSVReader[Person](
"/Users/robbypelssers/Documents/persons.csv",
",", List(NAME, AGE, IS_MALE),
true,
lineMapper
)
while (csvReader.hasNext) {
println(csvReader.next)
}
view raw gistfile1.scala hosted with ❤ by GitHub

No comments:

Post a Comment