Scala: фильтрация набора параметров

Скажем, у меня есть функция, которая проверяет применимость некоторой операции к экземпляру A и, если да, возвращает экземпляр B или None:

   def checker[A,B]( a: A ) : Option[B] = ...

Теперь я хочу создать новую коллекцию, содержащую все допустимые экземпляры B, отбрасывая значения None. Следующий код, кажется, выполняет эту работу, но, безусловно, есть лучший способ:

   val as = List[A]( a1, a2, a3, ... )
   val bs = 
     as
     .map( (a) => checker(a) )    // List[A] => List[Option[B]]
     .filter( _.isDefined )       // List[Option[B]] => List[Option[B]]
     .map( _.get )                // List[Option[B]] => List[B]

Спасибо!


person Gregor Scheidt    schedule 28.09.2011    source источник
comment
flatMap это дерьмо   -  person oxbow_lakes    schedule 28.09.2011
comment
@oxbow_lakes Я считаю, что правильная цитата: Что это? Любительский час? flatMap это дерьмо!   -  person Daniel C. Sobral    schedule 29.09.2011
comment
Эта цитата из твиттера?   -  person huynhjl    schedule 29.09.2011
comment
Откуда эта цитата? кто сделал это?   -  person Jonathan Neufeld    schedule 14.09.2018


Ответы (2)


Это должно сделать это:

val bs = as.flatMap(checker)
person Kim Stebel    schedule 28.09.2011
comment
У меня не работает по разным причинам: 1. вывод типа, 2. List#flatMap ожидает GenTraversableOnce. Правильно: as.flatMap{a => checker[A, B](a)} - person IttayD; 28.09.2011
comment
Я протестировал его с функцией от Int до Option[String]. В худшем случае вам придется добавить к нему несколько явных типов. - person Kim Stebel; 28.09.2011

Ответ выше правильный, но если вы можете переписать checker, я предлагаю вам использовать PartialFunction и collect. PartialFunction — это функция типа A=>B, которую не обязательно определять для всех значений A. Вот простой пример:

scala> List(1, 2, 3, 4, "5") collect {case x : Int => x + 42}
res1: List[Int] = List(43, 44, 45, 46)

collect принимает экземпляр PartialFunction в качестве аргумента и применяет его ко всем элементам коллекции. В нашем случае функция определена только для Ints, а "5" фильтруется. Итак, collect — это комбинация map и filter, как раз в вашем случае.

person E. Verda    schedule 28.09.2011
comment
collect действительно представляет собой комбинацию filter и затем map, но обычно это не работает в другом направлении (map затем filter), так как вам нужно определить фильтр в операторе case. Так что было бы здорово заменить последние два оператора OP (на .collect { case Some(x) => x }), но если checker включает какие-либо нетривиальные вычисления, чтобы решить, следует ли возвращать Some или None, это может быть сложно написать как частичную функцию. . - person Andrzej Doyle; 28.09.2011