如何根据具有任意元素的多个列表进行映射?

时间:2017-06-17 13:03:13

标签: scala scala-collections

我有以下型号:

case class Car(brand: String, year: Int, model: String, ownerId: String)
case class Person(firstName: String, lastName: String, id: String)
case class House(address: String, size: Int, ownerId: String)
case class Info(id: String, lastName: String, carModel: String, address: String)

我想基于以下列表构建List[Info]

val personL: List[Person] = List(Person("John", "Doe", "1"), Person("Jane", "Doe", "2"))
val carL: List[Car] = List(Car("Mercedes", 1999, "G", "1"), Car("Tesla", 2016, "S", "4"), Car("VW", 2015, "Golf", "2"))
val houseL: List[House] = List(House("Str. 1", 1000, "2"), House("Bvl. 3", 150, "8"))

应根据personL收集信息,例如:

val info = personL.map { p =>
      val car = carL.find(_.ownerId.equals(p.id))
      val house = houseL.find(_.ownerId.equals(p.id))
      val carModel = car.map(_.model)
      val address = house.map(_.address)
      Info(p.id, p.lastName, carModel.getOrElse(""), address.getOrElse(""))
      }

结果:

info: List[Info] = List(Info(1,Doe,G,), Info(2,Doe,Golf,Str. 1))

现在我想知道是否有一个比我的地图构造更简洁的表达式,它解决了我的问题。

3 个答案:

答案 0 :(得分:2)

这是一个选项,首先从ownerid构建地图到模型和地址,然后在循环访问人员列表时查找信息:

val carMap = carL.map(car => car.ownerId -> car.model).toMap
// carMap: scala.collection.immutable.Map[String,String] = Map(1 -> G, 4 -> S, 2 -> Golf)

val addrMap = houseL.map(house => house.ownerId -> house.address).toMap
// addrMap: scala.collection.immutable.Map[String,String] = Map(2 -> Str. 1, 8 -> Bvl. 3)

personL.map(p => Info(p.id, p.lastName, carMap.getOrElse(p.id, ""), addrMap.getOrElse(p.id, "")))
// res3: List[Info] = List(Info(1,Doe,G,), Info(2,Doe,Golf,Str. 1))

答案 1 :(得分:0)

我会说用于理解。如果你确切地需要那个结果在那种情况下类似于left join的结果那么理解仍然是丑陋的:

for {
  person  <- persons
  model   <- cars.find(_.ownerId == person.id).map(_.model).orElse(Some("")).toList
  address <- houses.find(_.ownerId == person.id).map(_.address).orElse(Some("")).toList
} yield Info(person.id, person.lastName, model, address)

请注意,在这种特殊情况下,您可以删除.toList调用,因为两个Option生成器出现在集合生成器之后。

如果您可以牺牲默认的型号/地址值,那么它看起来很简单:

for {
  person <- persons
  car    <- cars if car.ownerId == person.id
  house  <- houses if house.ownerId == person.id
} yield Info(person.id, person.lastName, car.model, car.address)

希望有所帮助。

答案 2 :(得分:0)

可能会使用map函数转换哈希映射中的各个列表并按键查找而不是为每个人的元素迭代所有这些列表可能会有帮助吗?