如何使用scala将具有列表值的案例类适当地平整到另一个案例类

时间:2019-02-06 00:43:49

标签: scala

我的案例类别为ContactPerson

case class Contact(id: String, name: String)
case class Person(id: String, name: String, age: Int, contacts: List[Contact])

让我说我有Person的列表:

val pesonList = List(
  Person(1, "john", 30, List(Contact(5,"mark"),Contact(6,"tamy"),Contact(7,"mary"))),
  Person(2, "jeff", 40, List(Contact(8,"lary"),Contact(9,"gary"),Contact(10,"sam")))
)

我需要对此pesonList进行展平并将其转换为以下列表:

case class FlattenPerson(personId: String, contactId: Option[String], personName: String)

所以结果将是:

val flattenPersonList = List(
  FlattenPerson(1,"john"),
  FlattenPerson(1,5,"mark"),
  FlattenPerson(1,6,"tamy"),
  FlattenPerson(1, 7"mary"),
  FlattenPerson(2,"jeff"),
  FlattenPerson(2,8,"lary"),
  FlattenPerson(2,9,"gary"),
  FlattenPerson(2,10,"sam")
)

我发现了一种看起来像在起作用的方法,但是剂量似乎是正确的方法……它可能会破裂,scala可能有一种更有效的方法。

这是我能想到的:

val people = pesonList.map(person => {
  FlattenPerson(person.id, None, person.name)
})

val contacts = pesonList.flatMap(person => {
  person.contacts.map(contact => {
  FlattenPerson(person.id, Some(contact.id), contact.name)
  })
})

val res = people ++ contacts

这也将导致性能下降,我需要为我的应用获得的每个api调用执行此操作,并且它可以分配调用,还需要过滤res。

希望在这里获得帮助

2 个答案:

答案 0 :(得分:3)

我认为flatMap()可以满足您的需求。

personList.flatMap{pson =>
  FlattenPerson(pson.id, None, pson.name) :: 
    pson.contacts.map(cntc => FlattenPerson(pson.id, Some(cntc.id), cntc.name))
}
//res0: List[FlattenPerson] = List(FlattenPerson(1,None,john)
//                               , FlattenPerson(1,Some(5),mark)
//                               , FlattenPerson(1,Some(6),tamy)
//                               , FlattenPerson(1,Some(7),mary)
//                               , FlattenPerson(2,None,jeff)
//                               , FlattenPerson(2,Some(8),lary)
//                               , FlattenPerson(2,Some(9),gary)
//                               , FlattenPerson(2,Some(10),sam))

答案 1 :(得分:0)

这里供参考,是该算法的递归版本,其中包括单次过滤。这似乎比在结果上调用.filter(f)更快。未过滤的递归版本没有实际的性能优势。

def flattenPeople(people: List[Person], f: FlattenPerson => Boolean): List[FlattenPerson] = {
  @annotation.tailrec
  def loop(person: Person, contacts: List[Contact], people: List[Person], res: List[FlattenPerson]): List[FlattenPerson] =
    contacts match {
      case Contact(id, name) :: tail =>
        val newPerson = FlattenPerson(person.id, Some(id), name)
        if (f(newPerson)) {
          loop(person, tail, people, newPerson +: res)
        } else {
          loop(person, tail, people, res)
        }
      case _ =>
        val newPerson = FlattenPerson(person.id, None, person.name)
        val newRes =  if (f(newPerson)) newPerson +: res else res
        people match {
          case p :: tail =>
            loop(p, p.contacts, tail, newRes)
          case Nil =>
            newRes.reverse
        }
    }

  people match {
    case p :: tail => loop(p, p.contacts, tail, Nil)
    case _ => Nil
  }
}