Will.Whim

A weblog by Will Fitzgerald

Category Archives: Scala

Scala partial functions, map, and filter

Yesterday, I was writing some code that needed to (1) go over a collection of stored database objects, conditionally convert some of these to another version of themselves, and filter out some of them. For some reason, I got myself tripped up on some very basic things, and so here are some notes for myself and perhaps for others. (There were some other things going on, for one, support website pagination, but I won’t discuss that here).

The simplest way to handle is to use filter and map on the collection. For example, let’s say we want to remove, from a collection of integers, all odd numbers, and halve all the remaining numbers if they are a multiple of 4:

scala> (1 to 12).filter{_ % 2 == 0}.map{i => if (i % 4 == 0) i/2 else i}
res43: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 2, 6, 4, 10, 6)

Simple enough, of course: filter, then map, though map then filter might make sense in other cases (but of course here there is less “work” if we filter first).

Another possibility was to use partial functions, using collect. This can allow mapping and filtering to take place in the same step. In Scala’s terms, a partial function is a function from only some values of its argument. For example, if a function only applied to even Ints, then this function would be partial. This is, in effect,what we are saying the filter step does above. So we can get the same effect using collect:

scala> (1 to 12).collect{case i if i % 2 == 0 => if (i % 4 == 0) i/2 else i}
res44: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 2, 6, 4, 10, 6)

It’s a tool to have in one’s toolbox, but I think the “filter, then map” is clearer code. Interestingly, the first version is even a little shorter than the second.

Scala filters

A random Scala note.

Today, I wanted to apply a list of filters to each item in a list, and return just those that pass each of the filters.

For example, given a range of integers, return just those that are divisible by 2 and by 3.

Let’s start by defining a boolean function divides:

def divides(d:Int,i:Int) = if (i%d==0) true else false

Note that divides(2,_:Int) defines the (partial) function for division by 2.

(divides(2,_:Int))(2) => true
(divides(2,_:Int))(3) => false

So we can create our filters so:

val filters = divides(2,_:Int) :: divides(3,_:Int) :: Nil

or

val filters = List(divides(2,_:Int),divides(3,_:Int))

Now, we can simply use Scala’s filter and forall functions to filter a range of integers:

scala> Range(1,50).filter(x => filters.forall(f => f(x)))
res45: scala.collection.immutable.IndexedSeq[Int] =
  Vector(6, 12, 18, 24, 30, 36, 42, 48)

The filters could also be defined as a Set, but by creating them as a List, one can put the less expensive filters first.

Useful Scala introduction