在scala中读取类层次结构CSV的通用方法

在scala中读取类层次结构CSV的通用方法,scala,csv,generics,generic-programming,shapeless,Scala,Csv,Generics,Generic Programming,Shapeless,我知道有各种各样的库可以在scala中阅读CSV。我尝试过不成形的方式,但我在以一般方式读取层次结构的csv时遇到了困难。例如,我需要这样的东西: abstract class A case class ChildOneOfA(i:Int,s:String) extends A case class ChildTwoOfA(i:Int,os:Option[String]) extends A` // Requires generic implementation of T which i

我知道有各种各样的库可以在scala中阅读CSV。我尝试过不成形的方式,但我在以一般方式读取层次结构的csv时遇到了困难。例如,我需要这样的东西:

abstract class A
case class ChildOneOfA(i:Int,s:String) extends A
case class ChildTwoOfA(i:Int,os:Option[String]) extends A`



//  Requires generic implementation of T which is subtype of A

def genericCSVReader[T]:GenericCsvRecordReader[T] = {
//Generic implementation to return csv record iterator/reader
}

首先,您的示例有点奇怪-每一行要么是一个int和一个字符串,要么是一个int和一个可选字符串?这与说每一行是一个int和一个可选字符串是一样的,您不需要这两个选项

但作为一个有用的例子,假设每一行要么是一个int和一个boolean,要么是一个int和一个可选的float(假设您不想使用
Eiter
\/
Xor
来表示析取):

使用及其模块,您实际上可以非常简单地解析它:

import kantan.csv.ops._
import kantan.csv.generic._

"""1,true
2,3.14
3,""".asCsvReader[A](',', false).foreach(println _)
asCsvReader
由import语句引入范围。它接受一个类型参数(解码每行的类型)和两个值参数(列分隔符和指示是否应跳过第一行的标志)

此代码输出:

Success(Alternative1(1,true))
Success(Alternative2(2,Some(3.14)))
Success(Alternative2(3,None))
请注意:

  • asCsvReader
    的返回值是类似于
    迭代器的结构,这意味着您永远不需要在内存中加载整个CSV
  • 每一行都被包装成一个
    成功
    失败
    ,解码从不抛出(除非您需要这样做,在这种情况下,您可以使用
    asUnsafeCsvReader

首先,您的示例有点奇怪-每行要么是一个int和一个字符串,要么是一个int和一个可选字符串?这与说每一行是一个int和一个可选字符串是一样的,您不需要这两个选项

但作为一个有用的例子,假设每一行要么是一个int和一个boolean,要么是一个int和一个可选的float(假设您不想使用
Eiter
\/
Xor
来表示析取):

使用及其模块,您实际上可以非常简单地解析它:

import kantan.csv.ops._
import kantan.csv.generic._

"""1,true
2,3.14
3,""".asCsvReader[A](',', false).foreach(println _)
asCsvReader
由import语句引入范围。它接受一个类型参数(解码每行的类型)和两个值参数(列分隔符和指示是否应跳过第一行的标志)

此代码输出:

Success(Alternative1(1,true))
Success(Alternative2(2,Some(3.14)))
Success(Alternative2(3,None))
请注意:

  • asCsvReader
    的返回值是类似于
    迭代器的结构,这意味着您永远不需要在内存中加载整个CSV
  • 每一行都被包装成一个
    成功
    失败
    ,解码从不抛出(除非您需要这样做,在这种情况下,您可以使用
    asUnsafeCsvReader

您能说说如何将此ADT表示为CSV吗?目的是CSV将遵循案例类的类型参数。像对于
ChildOneOfA(i:Int,s:String)
我将拥有
“1,HI\n 2,HELLO”
ChildOneOfA(i:Int,s:Option[String])
我可以拥有
1,n2,“嘿”
如果单个case类具有不同数量和类型的元素(例如
Boolean
Double
)?或者如果您有不同的案例类,具有相同数量和类型的元素?是的,这是绝对可能的。数字和类型将不同,但您能否给出一个示例,说明您在这些情况下设想的表示方式?您能否说明如何将此ADT表示为CSV?目的是CSV将遵守案例类的类型参数。像对于
ChildOneOfA(i:Int,s:String)
我将拥有
“1,HI\n 2,HELLO”
ChildOneOfA(i:Int,s:Option[String])
我可以拥有
1,n2,“嘿”
如果单个case类具有不同数量和类型的元素(例如
Boolean
Double
)?或者如果您有不同的案例类,具有相同数量和类型的元素?是的,这是绝对可能的。数量和类型会有所不同,但您能否给出一个您在这些案例中设想的表示类型的示例?为了澄清我在问题下评论的各种案例类。其次,我尝试使用
//在我的程序新文件(fileName)中动态传递分隔符和头。asCsvReader[T](分隔符,头=头)
我得到
找不到kantan.csv.RowDecoder[T]类型的证据参数的隐式值。
我想我看到了问题。它不适用于抽象类。它适用于trait。这不是trait和abstract之间的区别,而是它必须被密封的事实。为了澄清各种各样的case类,我在问题下面进行了评论。其次,我尝试使用
//在我的程序新文件(fileName)中动态传递分隔符和头。asCsvReader[T](分隔符,头=头)
我得到
找不到kantan.csv.RowDecoder[T]类型的证据参数的隐式值。
我想我看到了问题。它不适用于抽象类。它适用于trait。这不是trait和abstract之间的区别,而是它必须被密封的事实。