如何为scala case类编写一个toCSV方法,为类生成csv字符串?

时间:2016-12-14 07:09:28

标签: scala csv

我有一个 scala案例类,如下所示。

case class Address(
              city: Option[String] = None,
              country: Option[String] = None
                )
case class Student(
              id: Option[String] = None,
              name: Option[String] = None,
              address: Option[Seq[Address]] = None,
              phone: Option[Seq[String]] = None
                )

现在我想为学生写一个 toCSV 方法,为每个学生生成一个 csv字符串/行列表。我无法确定如何为可能具有多个值的字段生成字符串格式,例如:address和phone。

对于学生,

val student_1 = Student(
              id = Some("1"),
              name = Some("john"),
              address = Some(Seq(
                         Address(Some("Newyork"),Some("USA")),
                         Address(Some("Berlin"),Some("Germany")),
                         Address(Some("Tokyo"),Some("Japan")),
                         )),
              phone = Some(Seq(
                         "1111","9999","8888"
                         ))
              )

因此, student_1.toCSV 必须产生以下 csv字符串

id, name, address.city, address.country, phone
1 , John, Newyork     , USA            , 1111/9999/888
  ,     , Berlin      , Germany        , 
  ,     , Tokyo       , Japan          ,           

这是字符串的csv列表,其中第一个字符串代表第一行,依此类推。我需要为每个学生生成这个字符串列表。请注意,每个学生可能有多行,因为地址和电话可以有多个值。在这种情况下,学生John有3个地址和2个电话。 我如何在scala中实现这一点?

增加:

到目前为止,我正在努力生成一个csv行列表,即列表列表,其中每个列表将存储一行。 所以,列表如下所示:

List(
    List("id","name","address.city","address.country","phone"),
    List("1" ,"John","Newyork"     ,"USA"            ,"11111/22222"),
    List(""  ,""    ,"Berlin"      ,"Germany"        ,""),
    List(""  ,""    ,"Tokyo"       ,"Japan"          ,"")
    )

2 个答案:

答案 0 :(得分:1)

在此,我将您的Address类型简化为String,并保留了原始phone布局(即我在评论中抱怨的那个)。所以这更像是概念验证而不是成品。

val student = Student(Some("1")
  , Some("John")
  , Some(Seq("Newyork", "Berlin", "Tokyo"))
  , Some(Seq("1111","9999"))
)

student match {
  case Student(i,n,a,p) => 
    val maxLen = a.getOrElse(Seq("")).length max p.getOrElse(Seq("")).length
    Seq( Seq(i.getOrElse("")).padTo(maxLen,"")
       , Seq(n.getOrElse("")).padTo(maxLen,"")
       , a.getOrElse(Seq()).padTo(maxLen,"")
       , p.getOrElse(Seq()).padTo(maxLen,"")
       ).transpose
}
// res0: Seq[Seq[String]] = List( List(1, John, Newyork, 1111)
//                              , List(, , Berlin, 9999)
//                              , List(, , Tokyo, ))

答案 1 :(得分:0)

基于上述@jwvh提供的答案,

我想出了一个现在正在为我工​​作的解决方案:

val student_1 = Student(
id = Some("1"),
name = Some("john"),
address = Some(Seq(
  Address(Some("Newyork"),Some("USA")),
  Address(Some("Berlin"),Some("Germany")),
  Address(Some("Tokyo"),Some("Japan"))
)),
phone = Some(Seq(
  "1111","9999","8888"
))
)

 def csvHeaders:List[String] = {
    List("StudentId","Name","Address.City","Address.Province","Phones")
 }

 def toCSV:List[List[String]] ={
   val maximumLength = address.getOrElse(Seq.empty[Address]).length max    1 
  //phone.getOrElse(Seq.empty[String]).length for earlier case where phones were kept in separate rows , done by @jwvh above
   val idList = List.tabulate(maximumLength)(k => "    ").updated(0,id.getOrElse(""))
   val nameList = List.tabulate(maximumLength)(k => "    ").updated(0,name.getOrElse(""))
   val addressCityList = if(address.isDefined){
    address.get.map{
    k => k.city.getOrElse(" ")
    }.toList.padTo(maximumLength," ")
    } else{
    List.tabulate(maximumLength)(k => " ")
    }
    val addressProvinceList = if(address.isDefined){
    address.get.map{
    k => k.province.getOrElse(" ")
    }.toList.padTo(maximumLength," ")
    } else{
    List.tabulate(maximumLength)(k => " ")
    }
    val phoneList = if(phone.isDefined){
    List.tabulate(maximumLength)(k => "     ").updated(0,phone.get.padTo(maximumLength," ").mkString("/"))
    } else{
    List.tabulate(maximumLength)(k => " ")
    }
    val transposedList:List[List[String]] =     List(idList,nameList,addressCityList,addressProvinceList,phoneList).transpose

    transposedList.+:(csvHeaders)
 }

So, now student_1.toCSV will return:

 /*   List(
        List(StudentId, Name, Address.City, Address.Province,      Phones),      
        List(1, john, Newyork, USA, 1111/9999/8888), 
        List( ,  , Berlin, Germany,  ), 
        List( ,  , Tokyo, Japan,  )
       ) */