mapping+filtering

79 views
Skip to first unread message

Andy Coolware

unread,
Sep 20, 2012, 6:22:04 PM9/20/12
to scala-user
Hi,

I have a quite complex sequences being processed and at some point I
need to in a single point to map the value to something else while
potentially filtering that out from the sequence. Optimally the
map+filter function throws an expetion which makes it to skip that
all together.

Is there any canonical way of doing that?



Thx in advance,
Andy

Luke Vilnis

unread,
Sep 20, 2012, 6:24:48 PM9/20/12
to Andy Coolware, scala-user
One way people do this kind of thing is to use flatMap instead of map and return a length-1 sequence if the predicate matches, and an empty sequence if it fails. Would that work?

Luke Vilnis

unread,
Sep 20, 2012, 6:33:10 PM9/20/12
to Alec Zorab, Andy Coolware, scala-user
One limitation of "collect" (I think) is that it only works if you can define your predicate in terms of a pattern match on the input sequence, not if you want to exclude something depending on the result of an intermediate computation (like the result of the "map" step).

On Thu, Sep 20, 2012 at 6:29 PM, Alec Zorab <alec...@googlemail.com> wrote:
Another, more canonical way to do it might be to use the collect method, which has a signature like this:

def collect[B](f: PartialFunction[A, B]) : Seq[B]

which keeps only the elements for which f was defined.

Alec Zorab

unread,
Sep 20, 2012, 6:29:15 PM9/20/12
to Luke Vilnis, Andy Coolware, scala-user
Another, more canonical way to do it might be to use the collect method, which has a signature like this:

def collect[B](f: PartialFunction[A, B]) : Seq[B]

which keeps only the elements for which f was defined.
On 20 September 2012 23:24, Luke Vilnis <lvi...@gmail.com> wrote:

Alec Zorab

unread,
Sep 20, 2012, 6:38:30 PM9/20/12
to Luke Vilnis, Andy Coolware, scala-user
and of course, if you need to do the filter after the mapping anyway, then 

x map f withFilter p 

should be pretty low overhead.

On 20 September 2012 23:36, Alec Zorab <alec...@googlemail.com> wrote:
myList collect {case o if p(f(o)) => f(o)}

but yes, not ideal because you call f twice.

That said, I reckon you can pretty much by definition filter on the input if you can filter on the output.

Alec Zorab

unread,
Sep 20, 2012, 6:36:03 PM9/20/12
to Luke Vilnis, Andy Coolware, scala-user
myList collect {case o if p(f(o)) => f(o)}

but yes, not ideal because you call f twice.

That said, I reckon you can pretty much by definition filter on the input if you can filter on the output.

Andy Coolware

unread,
Sep 20, 2012, 6:56:45 PM9/20/12
to scala-user
It is more like a complex map function might fail and I need to
skip/filter that out.

Daniel Sobral

unread,
Sep 20, 2012, 7:16:08 PM9/20/12
to Andy Coolware, scala-user
First partition, and then do any remaining mapping on both sides.

val (l, r) = xs partition predicate
val rights = r map f
val lefts = l map g

If partitioning is really hard, then return an Either, and collect for
Left and Right the resulting output.

If you have trouble making returning an Either, you can combine that with try:

val processed = xs.map(x => try { Right(f(x)) } catch { case ex:
Exception => Left(g(x)) })
val rights = processed collect { case Right(x) => x }
val lefts = processed collect { case Left(x) => x }


>
>
>
> Thx in advance,
> Andy



--
Daniel C. Sobral

I travel to the future all the time.

Som Snytt

unread,
Sep 20, 2012, 7:50:21 PM9/20/12
to Andy Coolware, scala-user
On Thu, Sep 20, 2012 at 3:56 PM, Andy Coolware <andy.c...@gmail.com> wrote:
It is more like a complex map function might fail and I need to
skip/filter that out.

The guy with glasses who is ducking into the phone booth is called Try.

scala> def f(i: Int): Int = if (i == 3) throw new Exception("Three!") else i+1
f: (i: Int)Int

scala> val vs = List(1,2,3,4,5)
vs: List[Int] = List(1, 2, 3, 4, 5)

scala> import util._
import util._

scala> vs flatMap (i=> Try(f(i)).toOption)
res1: List[Int] = List(2, 3, 5, 6)

This is just the first previous answer above.

As usual, HTH and sorry if I missed the point entirely.

Alec Zorab

unread,
Sep 21, 2012, 2:18:48 AM9/21/12
to Som Snytt, scala-user, Andy Coolware

If this is happening anywhere that performance matters, you're probably better off partitioning beforehand, rather than just catching the exception.

Otherwise yeah, Try is the guy for you.

Naftoli Gugenheim

unread,
Sep 24, 2012, 7:06:42 PM9/24/12
to Alec Zorab, Luke Vilnis, Andy Coolware, scala-user
On Thu, Sep 20, 2012 at 6:36 PM, Alec Zorab <alec...@googlemail.com> wrote:
myList collect {case o if p(f(o)) => f(o)}

but yes, not ideal because you call f twice.

That much can be solved with an extractor -
object GetF { def unapply(o: O) = Some(f(o)) filter p }

However I think it will still be called redundantly, since it gets compiled into both isDefinedAt and apply. Then again, you can solve that too with a cache...

Andy Coolware

unread,
Sep 24, 2012, 8:45:07 PM9/24/12
to scala-user
Hi,

Thanks for all suggestions. I hoped this is somehow build into List
semantics but those are fine too,

Best,
Andy
Reply all
Reply to author
Forward
0 new messages