根据其他列表元素过滤列表元素

时间:2018-02-04 15:51:18

标签: scala list collections

我有2个列表:listalistb。对于lista中的每个元素,我想检查每个元素的a_type是否在b_type的{​​{1}}中。如果listb,请获取相应true的{​​{1}}并构建对象b_name。然后,我应该返回构造b_type的列表。

有没有办法在Scala中执行此操作,最好没有任何可变集合?

objc

3 个答案:

答案 0 :(得分:0)

列表中的查找需要在O(n)时间内遍历,这是低效的。因此,您要做的第一件事就是创建从b_typeb_name的地图:

val bTypeToBname = listb.map(b => (b.b_type, b_name)).toMap

然后,您遍历lista,在地图中查找给定b_name是否有相应的a.a_type,并构建objc

val cs = for {
  a <- lista
  b_name <- bTypeToBname.get(a.a_type)
} yield objc(a.a_id, a.a_type, b_name)

注意Scala for-comprehensions如何自动过滤那些未定义bTypeToBname(a.a_type)的情况:然后简单地跳过相应的a。这是因为我们使用bTypeToBname.get(a.a_type)(返回Option),而不是直接调用bTypeToBname(a.a_type)(这会导致NoSuchElementException)。据我所知,这种过滤正是你想要的行为。

答案 1 :(得分:0)

case class A(aId: String, aType: String)
case class B(bId: String, bType: String, bName: String)
case class C(cId: String, cType: String, cName: String)


def getNames(aList: List[A], bList: List[B]): List[C] = {
  val bMap: Map[String, B] = bList.map(b => b.bType -> b)(collection.breakOut)
  aList.flatMap(a => bMap.get(a.aType).map(b => C(a.aId, a.aType, b.bName)))
}

答案 2 :(得分:0)

与安德烈的答案相同,但没有理解,所以你可以看到里面发生了什么。

// make listb into a map from type to name for efficiency
val bs = listb.map(b => b.b_type -> b_name).toMap
val listc: Seq[objc] = lista
  .flatMap(a => // flatmap to exclude types not in listb
    bs.get(a.a_type) // get an option from blist
      .map(bName => objc(a.a_id, a.a_type, bName)) // if there is a b name for that type, make an objc
  )