在Scala中将map和filter的组合归零

时间:2012-01-20 09:03:39

标签: scala

是否可以通过一次调用表示map和null跳过来表达以下代码?

list.map(_.accept(this, arg).asInstanceOf[T]).filter(_ != null)

2 个答案:

答案 0 :(得分:11)

list flatMap { i => Option(i.accept(this, arg).asInstanceOf[T]) }

或者,如果您愿意,(尽管这会或多或少地转换为原始表达式)

for {
  item <- list
  itemConverted = item.accept(this, arg).asInstanceOf[T]
  itemNonNull = itemConverted if itemConverted != 0
} yield itemNonNull

使用collect是可能的,但由于部分函数的accept测试,它可能会在大多数参数上调用isDefinedAt两次:

list collect {
  case i if i.accept(this, arg).asInstanceOf[T] != null => i.accept(this, arg).asInstanceOf[T]
}

需要使用一些备忘录(或智能提取器)来避免这种情况。

答案 1 :(得分:7)

如果您担心效果,可以添加.view

list.view.map(_.accept(this, arg).asInstanceOf[T]).filter(_ != null)

view会导致遍历变得懒惰,因此mapfilter将在列表中的一次传递中执行,而不是两次单独传递。

如果您担心重复使用此模式,可以定义自己的辅助函数:

def mapNN[A,B](list: List[A])(f: A => B) = {
  list.view.map(f(_)).filter(_ != null)
}

mapNN(list)(_.accept(this, arg).asInstanceOf[T])

...测试

> mapNN(List(1,2,3))(x => if (x%2==0) x else null).toList
res7: List[Any] = List(2)