gpt4 book ai didi

scala - 将Scala中的CSV读取到具有错误处理的案例类实例中

转载 作者:行者123 更新时间:2023-12-03 15:15:01 25 4
gpt4 key购买 nike

我想在Scala中读取CSV字符串/文件,以便在给定案例类C和错误类型Error的情况下,解析器填充Iterable[Either[Error,C]]。有没有这样做的图书馆或类似的书?

例如,给定一个类和错误



case class Person(name: String, age: Int)

type Error = String


和CSV字符串

Foo,19
Ro
Bar,24


解析器将输出



Stream(Right(Person("Foo",1)), Left("Cannot read 'Ro'"), Right(Person("Bar", 24)))


更新:

我认为我的问题不清楚,所以让我澄清一下:是否有一种方法可以在Scala中读取CSV而无需定义样板?给定任何案例类,有没有办法自动加载它?我想以这种方式使用它:



val iter = csvParserFor[Person].parseLines(lines)

最佳答案

这是一个Shapeless实现,采用的方法与your proposed example中的方法略有不同。这是基于我过去编写的一些代码,与您的实现的主要不同之处在于该代码更具通用性-例如,实际的CSV解析部分已被剔除,因此可以轻松使用专用库。

首先是通用的Read类型类(尚无Shapeless):

import scala.util.{ Failure, Success, Try }

trait Read[A] { def reads(s: String): Try[A] }

object Read {
def apply[A](implicit readA: Read[A]): Read[A] = readA

implicit object stringRead extends Read[String] {
def reads(s: String): Try[String] = Success(s)
}

implicit object intRead extends Read[Int] {
def reads(s: String) = Try(s.toInt)
}

// And so on...
}


然后有趣的部分是:一个类型类,它提供从字符串列表到 HList的转换(可能会失败):

import shapeless._

trait FromRow[L <: HList] { def apply(row: List[String]): Try[L] }

object FromRow {
import HList.ListCompat._

def apply[L <: HList](implicit fromRow: FromRow[L]): FromRow[L] = fromRow

def fromFunc[L <: HList](f: List[String] => Try[L]) = new FromRow[L] {
def apply(row: List[String]) = f(row)
}

implicit val hnilFromRow: FromRow[HNil] = fromFunc {
case Nil => Success(HNil)
case _ => Failure(new RuntimeException("No more rows expected"))
}

implicit def hconsFromRow[H: Read, T <: HList: FromRow]: FromRow[H :: T] =
fromFunc {
case h :: t => for {
hv <- Read[H].reads(h)
tv <- FromRow[T].apply(t)
} yield hv :: tv
case Nil => Failure(new RuntimeException("Expected more cells"))
}
}


最后,使其与案例类一起使用:

trait RowParser[A] {
def apply[L <: HList](row: List[String])(implicit
gen: Generic.Aux[A, L],
fromRow: FromRow[L]
): Try[A] = fromRow(row).map(gen. from)
}

def rowParserFor[A] = new RowParser[A] {}


现在,我们可以使用例如 OpenCSV编写以下内容:

case class Foo(s: String, i: Int)

import au.com.bytecode.opencsv._
import scala.collection.JavaConverters._

val reader = new CSVReader(new java.io.FileReader("foos.csv"))

val foos = reader.readAll.asScala.map(row => rowParserFor[Foo](row.toList))


如果我们有这样的输入文件:

first,10
second,11
third,twelve


我们将得到以下内容:

scala> foos.foreach(println)
Success(Foo(first,10))
Success(Foo(second,11))
Failure(java.lang.NumberFormatException: For input string: "twelve")


(请注意,这会为每一行产生 GenericFromRow实例,但是如果您担心性能,则很容易更改它。)

关于scala - 将Scala中的CSV读取到具有错误处理的案例类实例中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27781020/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com