How do I find the min() or max() of two Option[Int]

Update: I just noticed that my solution below and the one in your answer behave differently—I read your question as asking for the minimum of the two values when there are two values, but in your answer you're effectively treating None as if it contained a value that's either bigger (for min) or smaller (for max) than anything else.

To be more concrete: if i1 is Some(1) and i2 is None, my solution will return the default value, while yours will return 1.

If you want the latter behavior, you can use the default semigroup instance for Option[A] and the tropical semigroup for Int. In Scalaz 7, for example, you'd write:

import scalaz._, Scalaz._

optionMonoid(Semigroup.minSemigroup[Int]).append(i1, i2) getOrElse defaultValue

Or the following shorthand:

Tags.Min(i1) |+| Tags.Min(i2) getOrElse defaultValue

It's not as clean as the applicative functor solution below, but if that's your problem, that's your problem.


Here's a more idiomatic way that doesn't involve creating an extra list:

(for { x <- i1; y <- i2 } yield math.min(x, y)) getOrElse defaultValue

Or, equivalently:

i1.flatMap(x => i2.map(math.min(x, _))) getOrElse defaultValue

What you're doing is "lifting" a two-place function (min) into an applicative functor (Option). Scalaz makes this easy with its applicative builder syntax:

import scalaz._, Scalaz._

(i1 |@| i2)(math.min) getOrElse defaultValue

The standard library solution isn't much less elegant in this case, but this is a useful abstraction to know about.


I solved a similar problem using the following approach. We handle a special case when both of the options have values, otherwise we use an API method Option.orElse.

val a: Option[Int]  = Some(10)
val b: Option[Int] = Some(20)
val c: Option[Int] = (a, b) match {
  case (Some(x), Some(y)) => Some(x min y)
  case (x, y) => x orElse y
}

val minValue: Int = List(i1, i2).flatten.sorted.headOption getOrElse defaultValue