Problem overview
oldestPet gets an ArrayBuffer[(String, Int)] called pets. Each pet is a tuple of its name and its age, like ("Rex", 4). The function returns the name of the oldest pet. When several pets share the oldest age, it returns the one that comes first in the list.
[("Rex", 4), ("Bella", 7), ("Max", 2)]givesBella.[("Luna", 3), ("Coco", 9), ("Milo", 9)]givesCoco, because Coco and Milo are both 9 and Coco is first.[("Kiki", 0)]givesKiki.
Approach
Keep the oldest pet seen so far in a variable called oldest, and walk through the list once. A pet replaces oldest only when it is older. Because the comparison is strictly greater, a pet of the same age never replaces the one already held, which keeps the first one on a tie.
The variable holds the whole tuple, not just the age. That way the name comes along, and the function can return it after the loop.
This is a single pass over the list with one extra variable, so there is nothing to sort. Sorting the pets by age would also work, but it does more work than the question needs.
Step by step
- Declare
oldestwithvar, starting with the first pet,pets(0). Before the loop looks at anything else, the first pet is the oldest one seen. - Loop with
pet <- pets. - Inside, check whether
pet._2 > oldest._2. A pet's age is its_2. - If it is older, set
oldest = pet. - After the loop, return
oldest._1, the name.
The solution in Scala
class Solution {
def oldestPet(pets: ArrayBuffer[(String, Int)]): String = {
var oldest = pets(0)
for (pet <- pets) {
if (pet._2 > oldest._2) {
oldest = pet
}
}
return oldest._1
}
}
The type of oldest is (String, Int), inferred from pets(0), so assigning pet to it is allowed. The loop starts at the first pet again, which compares it with itself and changes nothing.
The loop could also unpack each pet, as in for ((name, age) <- pets), but then you would need a second variable for the best name and another for the best age. Keeping the whole tuple means one variable.
Tracing the tie
Printing pet and oldest on each pass for the second example shows why the first of two equal ages wins:
pet=(Luna,3) oldest=(Luna,3)
pet=(Coco,9) oldest=(Coco,9)
pet=(Milo,9) oldest=(Coco,9)
Milo is 9, the same as Coco, so 9 > 9 is false and Coco stays.
Another way
Scala collections also have maxBy. pets.maxBy(p => p._2)._1 gives Coco for the same list, because maxBy returns the first element with the largest value. Writing the loop yourself first shows what that one call does.
Testing
[("Rex", 4), ("Bella", 7), ("Max", 2)] Bella
[("Luna", 3), ("Coco", 9), ("Milo", 9)] Coco
[("Kiki", 0)] Kiki
Edge cases and common mistakes
- Using
>=. On the second example, the loop would replace Coco with Milo, and the function would returnMilo. The lesson wants the first of the tied pets. - Returning the tuple. The function returns a
String, so returnoldest._1, notoldest. - Mixing up
_1and_2. The name is_1and the age is_2. Comparing names with>compiles for strings, but it compares alphabetically. - Starting with an age of 0. An age can be 0, as with Kiki, so a made-up starting value can hide a real pet. Starting from
pets(0)avoids that.
