Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combination of map and filter nulls out in Scala

Tags:

scala

Is it possible to express the following code in such a way that the map and null skipping is expressed in one call?

list.map(_.accept(this, arg).asInstanceOf[T]).filter(_ != null)
like image 610
Timo Westkämper Avatar asked Jan 20 '12 09:01

Timo Westkämper


2 Answers

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

or alternatively, if you like, (though this will be converted more or less to your original expression)

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

Using collect would be possible but it would likely call accept twice on most arguments because of the isDefinedAt test of the partial function:

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

One would need to use some memoising (or smart extractors) to avoid this.

like image 133
Debilski Avatar answered Nov 10 '22 19:11

Debilski


If you are concerned about performance, you can add .view

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

view causes the traversal to become lazy, thus the map and filter will be performed in one pass over the list rather than two separate passes.

If you are concerned about reusing this pattern, you can define your own helper function:

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

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

Testing...

> mapNN(List(1,2,3))(x => if (x%2==0) x else null).toList
res7: List[Any] = List(2)
like image 23
Dan Burton Avatar answered Nov 10 '22 21:11

Dan Burton