簡體   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