Built-ins for common jobs
Finding the largest value and adding numbers up are jobs that come up all the time, and you have written loops for both. Scala collections have them built in:
buf.mingives the smallest value ofbuf.buf.maxgives the largest value.buf.sumadds all the values up.
val prices = scala.collection.mutable.ArrayBuffer(4, 9, 2, 7)
println(prices.min)
println(prices.max)
println(prices.sum)
2
9
22
There are no parentheses after the names. They work the same way on an ArrayBuffer, an Array or a List. Each call looks at the whole collection and returns one value.
These are different from math.max(a, b), which compares just two values. buf.max looks at all the values in a collection.
Built-in versus loop
A loop that adds numbers needs a starting var total = 0, a for loop and a += line, and the loop for the largest value needs a starting candidate. Each of those is a chance for a slip, such as starting a maximum at 0 when every number is negative. The built-ins have the starting values right already, and they say in one word what you want. Use a loop when the job is more than a plain minimum, maximum or sum, for example when you also need to skip some values.
Other types
min and max work on any items that Scala knows how to order, not only numbers. List("pear", "fig", "apple").max is pear, because strings compare alphabetically. sum needs numbers.
Using the results together
The three values combine in ordinary arithmetic. With the week of minutes ArrayBuffer(25, 40, 15, 60, 30, 45, 20), minutes.max - minutes.min is 45, the gap between the longest and the shortest day. The average takes a little care. minutes.sum / minutes.length divides two Int values, so the fraction is cut off and the result is 33. Converting the sum first, with minutes.sum.toDouble / minutes.length, gives 33.57142857142857.
The sum of Int values is an Int, which has 32 bits and wraps around silently if the total is too large. A week of minutes is nowhere near that, but a very long list of big numbers could be.
Watch out for an empty collection
An empty collection has no smallest value. Calling min or max on it throws an UnsupportedOperationException, and the program stops with an error. Two safer methods, minOption and maxOption, return an Option instead: Some(value) when there is one, and None when the collection is empty.
val empty = scala.collection.mutable.ArrayBuffer[Int]()
println(empty.minOption.getOrElse(0))
println(empty.maxOption)
println(empty.sum)
0
None
0
getOrElse(0) picks a default for the empty case. sum of an empty collection is 0, so it needs no such care. For a non-empty buffer, maxOption gives, for example, Some(60).
The exercise
minutes holds how many minutes you practiced coding on each day of a week. Store the shortest day in shortest, the longest in longest and the week's total in total, using the built-ins. The code below prints all three.
val minutes = scala.collection.mutable.ArrayBuffer(25, 40, 15, 60, 30, 45, 20)
val shortest = minutes.min
val longest = minutes.max
val total = minutes.sum
println(s"shortest = $shortest")
println(s"longest = $longest")
println(s"total = $total")
The output is:
shortest = 15
longest = 60
total = 235
Common mistakes
- Using the loop from the earlier lessons when a built-in is enough. The built-in is shorter and has less room for mistakes, like starting a running maximum at the wrong value.
- Calling
minormaxon a collection that might be empty, withoutminOptionormaxOption. - Mixing up the index and the value.
maxgives the largest value, not its position.
Key takeaways
min,maxandsumreplace the usual loops and need no parentheses.- They fail on an empty collection for
minandmax; useminOptionandmaxOption. sumof an empty collection is 0.
