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 reply on “Scala Saturday – List.headOption”
[…] week, we looked at List.headOption. If you don’t need the first item in a list, but rather the last item, the counterpart of […]