将 Map 对象映射到 Option[Iterable[Row]] 以派生 Option[List[Address]]

mapping a Map object to an Option[Iterable[Row]] to derive an Option[List[Address]]

我有以下案例类:

case class Address (
                     val addressLine1: String,
                     val addressLine2: String,
                     val city: String,
                     val provinceCode: String,
                     val country: String,
                     val addressTypeDesc: String)

case class ClientData(
                        val title: String,
                        val firstName: String,
                        val lastName: String,
                        val addrList: Option[List[Address]]
                      ) 

我还有以下对象:

import org.apache.spark.sql.Row

object ClientBuilder {

  def build(client: Row, addr: Option[Iterable[Row]], addrType: Map[String, String]): ClientData = {

    // The object validates that the field “ClientTitle” is empty or one of the following values only:
    // "Mr.", "Ms.", "Mrs." - Otherwise the build will throw an IllegalArgumentException
    val title: String =
    client.getAs[String]("Title") match {
      case "Mr." => "Mr."
      case "Ms." => "Ms."
      case "Mrs." => "Mrs."
      case "" => ""
      case _ => throwException("Client Title is not as expected")
    }
    val firstName: String = client.getAs[String]("FirstName")
    val lastName: String = client.getAs[String]("LastName")

    val addrList: Option[List[Address]] = // having some problem figuring this part out

      ClientData(title, firstName, lastName, addrList)
  }

  def throwException(exceptionReason: String) = {
    throw new IllegalArgumentException(s"Exception thrown due to: ${exceptionReason}")
  }
}

addr: Option[Iterable[Row]]

有以下列:

AddressID,AddressLine1,AddressLine2,City,ProvinceName,ProvinceCode,Country,ClientID,AddressTypeCode

addrType: Map[String, String])

如下:

Map(1 -> "Billing", 2 -> "Home", 3 -> "Main Office", 4 -> "Primary", 5 -> "Shipping", 6 -> "Archive")

我想加入 addr: Option[Iterable[Row]]addrAddressTypeCode 上的 addrType: Map[String, String])addrType 键以获得 addressTypeDesc 并创建一个 Address 类型的列表。

好的,所以我设法通过遍历 Option[Iterable[Row]] 并使用 Option .get() 方法将 addrType 映射到 [ 中每个客户端的地址列表来解决它=12=]。这是我如何实现的:

object ClientBuilder {

  def build(client: Row, addr: Option[Iterable[Row]], addrType: Map[String, String]): ClientData = {

    // The object validates that the field “ClientTitle” is empty or one of the following values only:
    // "Mr.", "Ms.", "Mrs." - Otherwise the build will throw an IllegalArgumentException
    val title: String =
    client.getAs[String]("Title") match {
      case "Mr." => "Mr."
      case "Ms." => "Ms."
      case "Mrs." => "Mrs."
      case "" => ""
      case _ => throw new IllegalArgumentException(s"Exception thrown due to: Invalid Title. Title must be: Mr., Ms., Mrs., or empty.")
    }
    val firstName: String = client.getAs[String]("FirstName")
    val lastName: String = client.getAs[String]("LastName")

    // iterate through the Option[Iterable[Row]] and write each row to Option[Iterable[Address]]. 
    val addrList = Option(
      for(address <- addr.getOrElse(List()).toList) yield {
        Address(
          address.getAs("AddressLine1"),
          address.getAs("AddressLine2"),
          address.getAs("City"),
          address.getAs("ProvinceCode"),
          address.getAs("Country"),
          // using the getAs() method of the addrType Map object map get the AddressTypeDescription
          addrType.getOrElse(address.getAs("AddressTypeCode").toString,"No such address type") 
        )
      }
    )
    ClientData(title, firstName, lastName, addrList)
  }
}

然而,这可能不是最有效的方法。在与我的一位同事交谈后,他们建议使用以下方法:

object ClientBuilder {
  def build(client: Row, addr: Option[Iterable[Row]], addrType: Map[String,String]): ClientData = {
    val addrList: Option[List[Address]] =
      if (addr.isEmpty) None
      else
        Some(
          addr.get.map( (addrRow: Row) =>
            Address(
              addrRow.getAs[String]("AddressLine1")
              , addrRow.getAs[String]("AddressLine2")
              , addrRow.getAs[String]("City")
              , addrRow.getAs[String]("ProvinceCode")
              , addrRow.getAs[String]("Country")
              , addrType.get(addrRow.getAs[String]("AddressTypeCode")).getOrElse("")
            )
          ).toList
        )

    val firstName: String = DFAsist.safeGeteString(client, "FirstName").getOrElse("")
    val lastName: String = DFAsist.safeGeteString(client, "LastName").getOrElse("")
    val title: String = DFAsist.safeGeteString(client, "Title") match {
      case None => ""
      case Some(s) if List("Mr.", "Ms.", "Mrs.").contains(s) => s
      case _ => throw new IllegalArgumentException("Title is wrong!!!")
    }


    ClientData(title,firstName,lastName, addrList)
  }