Mapping an anonymous partial function

Hi,

I would like to do a pattern match on classes (with an extractor) using case keyword but if the case fails, keep the item and move on.

List(A(1),B(2),C(3)).map{ case B(2) => "here" }
will crash.
List(A(1),B(2),C(3)).collect{ case B(2) => "here" }
just provides an singleton list.

List(A(1),B(2),C(3)).map{ _ match { case B(2) => "here"; case otherwise => otherwise }}
feels too much.

I’m probably missing something simple here so apologies!

That’s pretty specialized - I don’t think I’ve ever wanted such a thing myself - but you could probably write a function to do it yourself.

I can’t do a fiddle for it right now (on the subway), but the idea is that you would write a function that takes a partial function and the value to match as its parameters. It would check whether the value is defined on the partial function (you can do that with partial functions). If so, you do the match; if not, just return the passed-in value…

List(A(1), B(2), C(3)).map { 
case B(2) => "here" 
case other => other 
} // produce List(A(1), here, C(3))

I’ve had occasional cases like that, and I think your third option is probably the best.

I’ve been thinking of doing something like

List(A(1),B(2),C(3)).map({ case B(2) => "here" }.orElse(identity)) // won't compile

but it doesn’t work, because orElse needs a PartialFunction and identity is not a PartialFunction. If you have this kind of situation more often in your code, you could make it work by creating your own identity:

def myIdentity[A]: PartialFunction[A, A] = { case a => a }

But then, your third option is maybe best.

List(A(1),B(2),C(3)).collect { case B(2) => “here”; case otherwise => otherwise }

works. Collect ignores things that don’t matches, maps things that do.

Brian Maso

@kotobotov solution is actually the proper one. case other => other works as a catch-all and turns the partial function into total function (needed for map to be safe). No need for collect in this case.

BTW:
You can omit semicolons even with one-liner pattern matching:

// compiles and works well
List(A(1), B(2), C(3)).map { case B(2) => "here" case other => other }
2 Likes