Scala - 转换和映射数据

时间:2014-07-22 00:18:14

标签: scala parsing csv

我将阅读的原始数据文件是制表符分隔的,其中一个字段是时间戳:

timestamp  userId  keyword
1405377264  A      google
1405378945  B      yahoo
1405377264  C      facebook

我有一个案例类定义为:

case class Event(date: String, userId: Int, keyword: String)

如何将时间戳转换为Date格式,然后映射到Event case类?我有将时间戳转换为日期的逻辑:

import java.text.SimpleDateFormat
import java.util.Date

val df = new SimpleDateFormat("yyyy-MM-dd")
val dt = new Date(timestamp*1000L)
val date = df.format(dt) 

转换原始数据并将其映射到案例类的正确方法是什么?

谢谢!

2 个答案:

答案 0 :(得分:3)

我不知道我是否说这是正确的方式,但是读取每一行的一种方法是使用正则表达式提取。假设您已将数据作为字符串,每个行标签分隔,每行由换行符(\n)分隔:

val data: String = ...
val regex = "(\\d+)\t([A-z])\t([A-z]+)".r

data.split('\n').map { line =>
    val regex(timestamp, userId, keyword) = line 
    Event(df.format(new Date(timestamp.toLong*1000L), userId, keyword)
}

按原样,如果与正则表达式有任何偏差(这必须根据您的需要进行调整,我只能遵循上面的示例),这不是容错的。例如,如果您想丢弃不符合的行,可以使用Trycollect

data.split('\n').map { line =>
    Try {
       // same as above
    }
}.collect {
    case Success(event) => event
}

答案 1 :(得分:2)

如何使用scala.io.Source.fromFile(myFile.csv).getLines读取CSV文件?这应该返回一个Iterator [String],这是一个懒惰的集合!

您可以在每一行上映射以创建一个事件。但你想要的是在创建Event对象之前将时间戳转换为java.util.Date作为第一步。

我会在这些方面提出一些建议:(这可能无法编译,但它应该给你基本的想法)

scala.io.Source.fromFile(myFile.csv).getLines flatMap { line =>
  splitAtDelimiter(line).toList match {
  case ts :: id :: kw :: Nil => 
    val date: Option[String] = 
      try { Some(convertToDateString(ts)) } catch { case e: Throwable => None }
    date.map(Event(_, getUserIdColumn(line), getKeyWordColumn(line)) // returns an Option[Event]
  case _ => None
}

你的convertToDateString是一个函数,它接受时间戳值并将其转换为java.util.Date,然后在其上执行toString(查看事件案例类中日期类型所需的内容) )splitAtDelimiter是一个虚构的CSV解析器函数!