4

I have a Scala value of type Option[Set[String]] that I am trying to use in a collection filter method:

val opt: Option[Set[String]] = ...

collection.filter {
  value =>
  opt match {
    case Some(set) => set.contains(value)
    case None => true
  }
}

If the opt value is Some(...) I want to use the enclosed Set to filter the collection, otherwise I want to include all items in the collection.

Is there a better (more idiomatic) way to use the Option (map, filter, getOrElse, etc.)?

The opt comes from an optional command line argument containing a list of terms to include. If the command line argument is missing, then include all terms.

Artemis
  • 2,553
  • 7
  • 21
  • 36
Ralph
  • 31,584
  • 38
  • 145
  • 282

2 Answers2

8

I'd use the fact that Set[A] extends A => Boolean and pass the constant function returning true to getOrElse:

val p: String => Boolean = opt.getOrElse(_ => true)

Or:

val p = opt.getOrElse(Function.const(true) _)

Now you can just write collection.filter(p). If you want a one-liner, either of the following will work as well:

collection filter opt.getOrElse(_ => true)
collection filter opt.getOrElse(Function.const(true) _)
Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • What is a purpose of Function.const(...) BTW? – om-nom-nom May 18 '12 at 12:47
  • 1
    @om-nom-nom http://stackoverflow.com/questions/5924875/whats-the-purpose-of-function-const – tenshi May 18 '12 at 12:56
  • If the collection contains a custom class instead of `String`, is there any way to check one of the instance fields (for example `name`) using your method? If a do a `map` on the collection to convert it to `String`, I lose the class contents, which I need later in the method chain. BTW, your method has worked very nicely for my String collections. Thanks. – Ralph May 18 '12 at 16:10
  • @Ralph: If you've defined `p` as above you can just use `collection.filter(x => p(x.name))`. – Travis Brown May 18 '12 at 16:26
6

It seems a bit wasteful to filter on _ => true so I would prefer

opt match {
  case Some(s) => collection filter s
  case None    => collection
}

I guess this equates to:

opt map (collection filter) getOrElse collection
Luigi Plinge
  • 50,650
  • 20
  • 113
  • 180
  • I agree that your solution is cleaner than the original version, and might be preferable for large collections, inside loops, etc., but in this case it feel like premature optimization—this is an operation that presumably only happens once, and on a very small collection (command line arguments), so I'd pick the more expressive version. – Travis Brown May 18 '12 at 14:42