Why custom sorting
sorted puts numbers from small to large and strings from A to Z. Often you need another order: the highest price first, the shortest word first, or names ordered by their last letter. For that, give sortBy a small function that says what to sort each item by. The function w => w.length has no name. It gets one value, w, and returns its length. sortBy then sorts the items by what the function returns.
Three common rules
sortBy(w => w.length)sorts by length, shortest first.sortBy(n => (n % 10, n))uses two rules. The function returns a tuple: the last digit, then the number. Tuples are compared item by item, so numbers with the same last digit go from small to large.sortBy(s => -s)sorts numbers from high to low: the biggest number has the smallest-s.
val nums = scala.collection.mutable.ArrayBuffer(25, 13, 5, 41, 33)
val byLastDigit = nums.sortBy(n => (n % 10, n))
Printed, byLastDigit is ArrayBuffer(41, 13, 33, 5, 25). The first item of the tuple sorts by last digit; the second puts 13 before 33 and 5 before 25.
Things to know
sortBymakes a newArrayBufferand leaves the old one as it was. WithwordsholdingArrayBuffer(pear, fig, apple),words.sortBy(w => w.length)givesArrayBuffer(fig, pear, apple), andwordsstill printsArrayBuffer(pear, fig, apple).- To sort an
ArrayBufferitself, usesortInPlaceByinstead. Afterwords.sortInPlaceBy(w => w.length),wordsprintsArrayBuffer(fig, pear, apple). - The
-strick has one trap:-Int.MinValueis stillInt.MinValuebecauseIntoverflow wraps silently. ForArrayBuffer(Int.MinValue, 3),sortBy(s => -s)leavesInt.MinValuefirst, which is wrong for high to low. Ordinary prices are safe.
The lesson's task
A pet shop has toy prices 12, 5, 30 and 8, and pets Rex, Luna, Bella, Max, Bo and Coco. Make highFirst with the prices from high to low, and byLastLetter with the names sorted by their last letter, with names that share a last letter going from A to Z.
- Call
sortByonpriceswith a function that turns eachpriceinto-price. The biggest price has the smallest-price, so it comes first. - For the names, call
sortBywith a function that returns the tuple(name(name.length - 1), name). The first item is the last letter: a string indexed with parentheses gives aChar, and chars sort in alphabetical order. - The second item is the name itself, so names with the same last letter go from A to Z. Max and Rex both end in x, and this puts Max first.
class Solution {
def mainFunction(): Unit = {
val prices = scala.collection.mutable.ArrayBuffer(12, 5, 30, 8)
val names = scala.collection.mutable.ArrayBuffer("Rex", "Luna", "Bella", "Max", "Bo", "Coco")
val highFirst = prices.sortBy(price => -price)
for (price <- highFirst) {
println(price)
}
val byLastLetter = names.sortBy(name => (name(name.length - 1), name))
for (name <- byLastLetter) {
println(name)
}
}
}
The prices print as 30, 12, 8, 5. The names end in a (Bella, Luna), o (Bo, Coco) and x (Max, Rex), so they print as:
Bella
Luna
Bo
Coco
Max
Rex
Common mistakes
- Expecting the original buffer to change.
sortByreturns a new one; print that one, notpricesornames. - Forgetting the second rule. With only the last letter, names that share it keep whatever order they started in.
- Mixing up the direction.
sortBy(s => s)goes small to large;-sflips it for numbers.
Key takeaways
sortBysorts by what a small function returns for each item.- Return a tuple for several rules; later items only matter on ties.
- Negating a number sorts high to low;
sortByreturns a new buffer,sortInPlaceBychanges the old one.
