将 Map 对象映射到选项[可迭代[行]]以派生选项[列表[地址]]



我有以下案例类:

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 映射到Option[Iterable[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 _ => 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)
}

最新更新