当前位置: 首页 > 知识库问答 >
问题:

如何使用shapeless从大平面csv文件中过滤和提取case类对象?

邢嘉祯
2023-03-14

我有一个大的扁平反规范化csv文件,其中包含单行上的多个对象,如下所示:

a1, a2, a3, b1, b2, b3 ...
...

我有对象:

case class A(a1: Int, a2: String, a3: Float)
case class B...
...

遗留的问题是编写复杂的适配器来提取每个类。我最近读了一些关于shapless的讨论,我知道我可以用shapless的泛型编程来解决这个问题。

甚至还有一个csv解析器示例,完美。我的想法是:

  1. 将csv解析为List[String]
  2. 用对象字段信息过滤ListString
  3. 使用过滤后的ListString并将其与Csv Parser示例一起提供
  4. 因此,我可以从csv文件中提取一行多个对象。

我遇到的问题:

>

  • 我仍然在scala 2.10上,我似乎已经正确配置了编译器插件(例如。mvn干净安装正常工作)。但是intellij偶尔会编译失败,引发异常。

    <groupId>org.scala-lang.plugins</groupId>
    <artifactId>macro-paradise_2.10</artifactId>
    <version>2.0.0-SNAPSHOT</version>
    

    此代码来自示例

    implicit def deriveHConsOption[V, T <: HList](
        implicit
        scv: Lazy[CSVConverter[V]],
        sct: Lazy[CSVConverter[T]]
      ):CSVConverter[Option[V] :: T] = new CSVConverter[Option[V] :: T] {
        override def from(s: String): Try[shapeless.::[Option[V], T]] = s.span(_ != ',') 
    

    但是,我有以下编译器错误:

    错误:(70,28)类型参数的数目错误,应为1:CSVConverter[Option[V]::T]=新的CSVConverter[Option[V]::T]{^

    我尝试使用shapeless过滤csv:

    //code to filter and extract one object 
    def extractCSVColumnsAndParse[T]:
        val labl = LabelledGeneric[T]
        val keys = Keys[labl.Repr].apply
        val keyNames = keys.toList.map(_.name)
    

    然而,似乎T只能是具体的类类型

    错误:(86,35)找不到参数lgen的隐式值:未成形。LabelledGeneric[T]val labl=LabelledGeneric[T]

  • 共有1个答案

    陈寒
    2023-03-14

    我对你的智能问题了解不多,但我会给另外两个答案:

    >

  • 2:::scala.collection.immutable.::List构造函数),除非您显式导入shapless.::HList构造函数)。

    3: 在处理泛型类型时,不能对其进行任何假设。它们可能是Int、Any、MyCaseClass、Nothing。。。因此,编译器无法为它们找到一个标签线(实际上,任何的标签线是什么?)。因此,您必须明确告诉所有泛型方法,您的类型有一个LabelledGeneric[T]的实例,这是通过将其作为隐式参数(或上下文边界,这是相同的事情,在引擎盖下)来实现的。例如,你可以

    // alternatively, def extractCSVColumnsAndParse[T: LabelledGeneric]
    def extractCSVColumnsAndParse[T](implicit ev: LabelledGeneric[T]) = {
      val labl = LabelledGeneric[T]
      val keys = Keys[labl.Repr].apply
      val keyNames = keys.toList.map(_.name)
      ...
    }
    

    然后,当您使用它时,对于显式case类:

    extractCSVColumnsAndParse[MyCaseClass]  //no need to pass the parameter, it is already in scope
    

    shapeless的“魔力”在于它为您生成隐式ev:LabelledEnergic[MyCaseClass],但它只能对特定类型(使用宏)执行此操作,因此如果您处理泛型类型,您必须告诉编译器它存在。

    编辑

    之后,您会得到一个错误,因为键的类型参数必须是HList,所以您必须以某种方式强制执行,因为Repr不一定是HList。此外,您还需要提供一个隐式的键[Repr],其原因与LabelledGeneric相同。

    def extractCSVColumnsAndParse[T, Repr <: HList](labl: LabelledGeneric.Aux[T, Repr], K: Keys[Repr]) {
      val keys = K()
      val keyNames = keys.toList.map(_.name)
      ...
    }
    

    但是,这使得使用特定case类调用变得不那么容易,因为您不能再执行提取CSVClonsAndParse[MyCaseClass]了。这是因为scala方法只有一个类型参数列表,所以您必须给它们全部或全部。

    避免这种情况的一种复杂方法是以下模式,假设您的方法实际上将有一些参数(例如,csv文件中的List[String]或csv文件路径):

    def extractCSVColumnsAndParse[T] = new Extractor[T]
    
    trait Extractor[T] {
      def apply[Repr <: HList](csv: List[String])(implicit labl: LabelledGeneric.Aux[T, Repr], K: Keys[Repr]) = {
        ... // put the logic here
      }
    }
    

    现在你可以用

    extractCSVColumnsAndParse[MyCaseClass](csv)
    

    此模式允许您仅指定第一个类型参数,第二个在编译时推断。

  •  类似资料:
    • 我正在尝试编写一个Python代码来打开一个csv文件,从特定列中过滤关键字并显示结果。 csv文件有500行和7列,以逗号分隔。 这是我的密码。不确定这是否有意义。

    • 如何从CSV文件中提取列? 我对Java有点陌生。你如何从csv文件中提取特定列。例如,如果我有这个数据: 如何提取第一列和第三列?我能够读取整个CSV文件,但我想从中提取特定的列。

    • 问题内容: 我有一个看起来像这样的csv文件 我想要一张桌子: 如果我使用,我会得到 吗?有什么优雅的方法吗? 问题答案: 您可以用来解析CSV文件,而不必担心自己解析。 PHP手册中的示例:

    • 问题内容: 当我卷曲到API调用链接时http://example.com/passkey=wedsmdjsjmdd 我以csv文件格式获取员工输出数据,例如: 如何使用python解析。 我试过了: 但它不起作用,我出现了一个错误 谢谢! 问题答案: 您需要替换为urllib.urlopen或urllib2.urlopen。 例如 这将输出以下内容 最初的问题被标记为“ python-2.x”,

    • 我需要从大文件中提取文本(最大限制50MB)文件可能是doc、ppt、xls、txt或pdf格式。到目前为止,我使用了ApachePOI'http://poi.apache.org/' 用于Microsoft Office文档和PDFBox从PDF中提取文本。然而,随着文件变大,提取过程变得缓慢,特别是以下文件。到目前为止我取得的成果: 1. PPTX-45MB-3分钟apx 2.PDF-62MB