Комбинация карт и нулевых фильтров в Scala - PullRequest
7 голосов
/ 20 января 2012

Можно ли выразить следующий код таким образом, чтобы пропускание карты и нулей выражалось в одном вызове?

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

Ответы [ 2 ]

11 голосов
/ 20 января 2012
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]
}

Чтобы избежать этого, нужно использовать некоторые заметки (или умные экстракторы).

7 голосов
/ 21 января 2012

Если вас беспокоит производительность, вы можете добавить .view

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

view, чтобы обход стал ленивым, поэтому map и filter будут выполняться за один проходчерез список, а не через два отдельных прохода.

Если вы хотите повторно использовать этот шаблон, вы можете определить свою собственную вспомогательную функцию:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...