Scala Saturday – List.headOption

Sometimes you need to get the first element of a list. No problem: List.head to the rescue, right? But what happens when you call List.head on an empty list?

val xs = List[Int]()
val h = xs.head
// java.util.NoSuchElementException: head of empty list

Well that’s not good. You could get around that little wart with this:

val xs = List[Int]()
val h = xs match {
  case h :: _ => h
  case Nil => -1
}

That’s not great. Alternatively, there’s this:

val xs = List[Int]()
val h = if (xs.isEmpty) -1 else xs.head
// h: Int = -1

Yeah, I’m not wild about those options either.

Speaking of options, what if you had a method that returns a None if you ask for the head of an empty list? If the list is not empty, it could return a Some containing the value of the head element. List.headOption does just that.

val empty = List[Int]()
val nonempty = (9 to 17).toList

val nuthin = empty.headOption
// nuthin: Option[Int] = None

val sumthin = nonempty.headOption
// sumthin: Option[Int] = Some(9)

Now you can use Option.getOrElse on the result of a call to List.headOption in order to return a default value in the event of an empty list:

val empty = List[Int]()
val nonempty = (9 to 17).toList

val head = nonempty.headOption getOrElse -1
// head: Int = 9

val fallback = empty.headOption getOrElse -1
// fallback: Int = -1

Now when might you actually use something like this? Perhaps you want to determine the top salesman each day, but only if the salesman has reached a certain threshold, say, $10,000. You can filter out the salesmen who don’t reach the threshold, sort the list of salesmen according to end-of-day sales totals, and then try to take the head element. If no one makes the cut, then the filter operation returns an empty list, which ultimately yields a None.

case class Salesman(name: String, sales: BigDecimal)

def findTopSalesman (salesmen : List[Salesman]) = {
  salesmen.filter { _.sales >= 10000 }
    .sortBy { -_.sales } // descending
    .headOption
}

So then, if Monday’s sales are as follows, then no one gets the prize because no one has broken $10,000:

val monday = List(
  Salesman("Joe Bob", 9500),
  Salesman("Sally Jane", 8500),
  Salesman("Betty Lou", 9800),
  Salesman("Sammy Joe", 6500)
)

val mondayTop = findTopSalesman(monday)
// mondayTop: Option[Salesman] = None

On Tuesday, though, there are two contenders. Alas, there can be only one winner, and Sally Jane (who, ironically, is from British Columbia) takes the prize:

val tuesday = List(
  Salesman("Joe Bob", 9500),
  Salesman("Sally Jane", 18500),
  Salesman("Betty Lou", 11800),
  Salesman("Sammy Joe", 6500)
)

val tuesdayTop = findTopSalesman(tuesday)
// tuesdayTop: Option[Salesman] = 
//   Some(Salesman(Sally Jane,18500))

One thought on “Scala Saturday – List.headOption”

Leave a Reply

Your email address will not be published. Required fields are marked *