在地图中组合过滤器

时间:2013-11-18 19:01:01

标签: scala map filter

我有一个列表,我通过调用相应的值计算函数以这种方式组合到一个地图。我使用collection.breakout来避免创建不必要的中间集合,因为我正在做的是有点组合,并且每一点保存的迭代都有帮助。

我需要从地图中过滤掉某些元组,在我的情况下,值小于0.是否可以将其添加到地图本身而不是之后再执行filter(因此再次迭代)?

val myMap: Map[Key, Int] = keyList.map(key => key -> computeValue(key))(collection.breakOut)

val myFilteredMap  = myMap.filter(_._2 >= 0)

换句话说,我希望一次性理想地获得第二张地图,理想情况下,在map()的第一次调用中,我会过滤掉我不想要的元组。这有可能吗?

2 个答案:

答案 0 :(得分:4)

最好做一个flatMap:

import collection.breakOut
type Key = Int
val keyList = List(-1,0,1,2,3)
def computeValue(i: Int) = i*2

val myMap: Map[Key, Int] = 
  keyList.flatMap { key => 
    val v = computeValue(key)
    if (v >= 0) Some(key -> v)
    else None
  }(breakOut)

您可以使用collect

val myMap: Map[Key, Int] = 
  keyList.collect { 
    case key if computeValue(key) >= 0 => key -> computeValue(key) 
  }(breakOut)

但这需要重新计算computeValue(key),这很愚蠢。当您过滤然后地图时,收集会更好。

或制作自己的方法!:

import scala.collection.generic.CanBuildFrom
import scala.collection.TraversableLike

implicit class EnrichedWithMapfilter[A, Repr](val self: TraversableLike[A, Repr]) extends AnyVal {
  def maptofilter[B, That](f: A => B)(p: B => Boolean)(implicit bf: CanBuildFrom[Repr, (A, B), That]): That = {
    val b = bf(self.asInstanceOf[Repr])
    b.sizeHint(self)
    for (x <- self) { 
      val v = f(x)
      if (p(v))
        b += x -> f(x)
    }
    b.result
  }
}

val myMap: Map[Key, Int] = keyList.maptofilter(computeValue)(_ >= 0)(breakOut)

答案 1 :(得分:4)

您可以使用foldLeft

轻松完成此操作
keyList.foldLeft( Map[Key,Int]() ) {
  (map, key) => 
    val value = computeValue(key)
    if ( value >= 0 ) {
      map + (key -> value)
    } else {
      map
    }
}