繁体   English   中英

如何返回转换为我的案例类的成功解析的行

[英]How to return successfully parsed rows that converted into my case class

我有一个文件,每一行都是一个 json 数组。 我读取文件的每一行,并尝试将行转换为 json 数组,然后对于每个元素,我使用 json Spray 转换为 case 类。

到目前为止我有这个:

       for (line <- source.getLines().take(10)) {
          val jsonArr = line.parseJson.convertTo[JsArray]
          for (ele <- jsonArr.elements) {
            val tryUser = Try(ele.convertTo[User]) 
          }
        }

如何将整个过程转换为单行语句?

val users: Seq[User] = source.getLines.take(10).map(line => line.parseJson.convertTo[JsonArray].elements.map(ele => Try(ele.convertTo[User])

错误是:

发现:迭代器[无]

注意:我在所有示例中都使用了 Scala 2.13.6。


在这几行代码中有很多东西需要解压。 首先,我将分享一些我们可以用来生成一些有意义的输入的代码。

object User {

  import scala.util.Random

  private def randomId: Int = Random.nextInt(900000) + 100000
  private def randomName: String = Iterator
    .continually(Random.nextInt(26) + 'a')
    .map(_.toChar)
    .take(6)
    .mkString

  def randomJson(): String = s"""{"id":$randomId,"name":"$randomName"}"""
  def randomJsonArray(size: Int): String =
    Iterator.continually(randomJson()).take(size).mkString("[", ",", "]")

}

final case class User(id: Int, name: String)

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

import spray.json._
import DefaultJsonProtocol._

implicit val UserFormat = jsonFormat2(User.apply)

这只是一些脚手架来定义一些User域对象,并提出一种方法来生成此类对象数组的 JSON 表示,以便我们可以使用 JSON 库(在本例中为spray-json )将其解析回我们想要什么。

现在,回到你的问题。 这是一种将您的数据转换成其解析表示的可能方法。 它可能无法 100% 适合您想要做的事情,但是所涉及的数据类型及其工作方式存在一些细微差别:

val parsedUsers: Iterator[Try[User]] =
  for {
    line <- Iterator.continually(User.randomJsonArray(4)).take(10)
    element <- line.parseJson.convertTo[JsArray].elements
  } yield Try(element.convertTo[User])

第一个区别:请注意,我以一种形式使用for理解,其中迭代的“结果”不是副作用( for (something) { do something } ),而是for (something) yield { return a value }的实际值for (something) yield { return a value } )。

第二个区别:我明确要求使用Iterator[Try[User]]而不是Seq[User] 我们可以深入探讨为什么类型是它们在这里的主题,但简单的解释是for ... yield表达式:

  1. 返回与生成第一行中的类型相同的类型——如果您以val ns: Iterator[Int]; for (n<- ns) ...开头val ns: Iterator[Int]; for (n<- ns) ... val ns: Iterator[Int]; for (n<- ns) ...你会得到一个迭代器
  2. 如果嵌套生成器,则它们需要与“最外层”生成器的类型相同

你可以阅读更多关于for在内涵斯卡拉游Scala的图书

一种可能的消费方式如下:

for (user <- parsedUsers) {
  user match {
    case Success(user)  => println(s"parsed object $user")
    case Failure(error) => println(s"ERROR: '${error.getMessage}'")
  }

至于如何将其转换为“单行”, for推导式是编译器应用的语法糖,它将每个嵌套调用转换为flatMap并将最后一个转换为map ,如下例所示(产生等效的结果作为for上面for理解并且非常接近编译器自动执行的操作):

val parsedUsers: Iterator[Try[User]] = Iterator
  .continually(User.randomJsonArray(4))
  .take(10)
  .flatMap(line =>
    line.parseJson
      .convertTo[JsArray]
      .elements
      .map(element => Try(element.convertTo[User]))
  )

我想补充的一点是,您应该注意可读性。 有些球队喜欢for内涵,别人手动推出自己flatMap / map链。 建议编码人员酌情决定。


您可以在 Scastie 上使用此代码( 这里是带有flatMap / map调用的版本)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM